57
GTK+ par l'exemple par Nicolas Joseph (home) (Blog) Date de publication : 28 juin 2006 Ce tutoriel a pour but de vous guider dans la réalisation d'une interface graphique en C grâce à GTK+ au travers l'exemple de la réalisation d'un éditeur de texte.

par Nicolas Joseph (home) (Blog) - Le Phmètre - …lephmetre.fr/papers/gtk-cours.pdf · • GTK+ est développée en C et pour le langage C, cependant elle est disponible pour d'autres

  • Upload
    hathuy

  • View
    215

  • Download
    0

Embed Size (px)

Citation preview

GTK+ par lexemple

par Nicolas Joseph (home) (Blog)

Date de publication 28 juin 2006

Ce tutoriel a pour but de vous guider dans la reacutealisation dune interfacegraphique en C gracircce agrave GTK+ au travers lexemple de la reacutealisation dun eacutediteurde texte

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 2 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

I - IntroductionI-A - But de ce tutorielI-B - Connaissances requisesI-C - Quelques mots sur GTK+

I-C-1 - HistoriqueI-C-2 - StructureI-C-3 - Pourquoi utiliser GTK+

I-D - InstallationI-D-1 - WindowsI-D-2 - Linux

I-E - La philosophie GTK+I-F - Quelques notions de POOI-G - Notre premier programmeI-H - Code source

II - Notre premiegravere fenecirctreII-A - AperccediluII-B - CreacuteationII-C - AffichageII-D - DestructionII-E - Code source

III - Fermer notre fenecirctre gracircce aux boutonsIII-A - AperccediluIII-B - Les boutons poussoirIII-C - Code source

IV - Comment afficher plusieurs widgetsIV-A - AperccediluIV-B - Le problegravemeIV-C - La solutionsIV-D - Code source

V - Afficher le contenue dun fichierV-A - AperccediluV-B - Saisir du texteV-C - Ouvrir un fichierV-D - La petite touche finaleV-E - Code source

VI - Choisir un fichierVI-A - AperccediluVI-B - Utilisation dun GtkFileChooserFileVI-C - Code source

VII - InterludeVII-A - Code source

VIII - Sauvegarder les modificationVIII-A - AperccediluVIII-B - EnregistrerVIII-C - Enregistrer sousVIII-D - Code source

IX - Creacuteer un nouveau documentIX-A - AperccediluIX-B - Nouveau fichierIX-C - Code source

X - FermerX-A - AperccediluX-B - Fermer un fichierX-C - Enregistrer avant de fermer

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 3 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

X-D - Code sourceXI - Les barres de deacutefilement

XI-A - AperccediluXI-B - Ajouter des barres de deacutefilementXI-C - Code source

XII - Les menusXII-A - AperccediluXII-B - Creacuteation du menuXII-C - Code source

XIII - Les barres doutilsXIII-A - AperccediluXIII-B - Creacuteation dune barre doutilsXIII-C - Code source

XIV - Les racourcis clavierXIV-A - AperccediluXIV-B - Mise en place des raccourcis clavierXIV-C - Code source

XV - Messages derreurXV-A - AperccediluXV-B - Ameacutelioration de nos fonctions daffichage derreurXV-C - Code source

XVI - Ouvrir plusieurs fichiers en mecircme tempsXVI-A - AperccediluXVI-B - Mise en place des ongletsXVI-C - Changement de pageXVI-D - Fermer un ongletXVI-E - Fermer tous les ongletsXVI-F - Modifier le titre de la pageXVI-G - Code source

XVII - Afficher larborescence du disqueXVII-A - AperccediluXVII-B - Preacuteparons le terrainXVII-C - Creacuteation dun GtkTreeView

XVII-C-1 - Creacuteation du magasinXVII-C-2 - Affichage de larborescenceXVII-C-3 - Seacutelectionner un fichier

XVII-D - Code sourceXVIII - Notre signature

XVIII-A - AperccediluXVIII-B - Boicircte A proposXVIII-C - Code source

XIX - ConclusionXIX-A - Cest deacutejagrave fini XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 4 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

I - Introduction

I-A - But de ce tutoriel

Pour vous initier aux joies de la programmation dinterfaces graphiques plutocirct que de faire un catalogue de toutesles fonctions de la bibliothegraveque ce qui serait long et vite ennuyeux je vous propose de construire pas agrave pas uneapplication un eacutediteur de texte Pas un simple eacutediteur de texte histoire de faire le tour des possibiliteacutes de GTK+nous allons y ajouter pas agrave pas les fonctionnaliteacutes suivantes

bull Creacuteation ouverture enregistrement de fichiers textes

bull Possibiliteacute douvrir plusieurs fichiers gracircce agrave une navigation par onglets

bull Ouverture rapide dun fichier gracircce agrave une liste de fichiers

Rien dimpressionnant par rapport agrave un traitement de texte mais plus eacutevolueacute et plus pratique quun simple eacutediteurde texte Ce tutoriel est organiseacute de faccedilon agrave ajouter une nouvelle fonctionnaliteacute agrave chaque eacutetape tout en apprenantagrave maicirctriser un ou plusieurs eacuteleacutements de GTK+

Comme je viens de le dire il nest pas question de faire un catalogue de la bibliothegravequecependant avant dutiliser un nouveaux type de widget jen ferai une bregraveve descriptionqui pourra vous servir de pense becircte lors de vos futurs deacuteveloppements Cette descriptioncomportera un aperccedilu pour les widgets graphiques sa hieacuterarchie dheacuteritage ses fonctionsde creacuteations (constructeurs) les fonctions les plus utiliseacutees et les signaux importants dela classe

I-B - Connaissances requises

Le but de ce tutorial est dapprendre agrave maicirctriser GTK+ en partant de zeacutero ou presque en effet avant de vouloir creacuteerune interface graphique il vaut mieux bien connaicirctre le langage C en mode console Pour cela je vous renvoie aucours de la rubrique C

I-C - Quelques mots sur GTK+

I-C-1 - Historique

GTK+ ou the GIMP Toolkit eacutetait agrave lorigine une boicircte agrave outils pour les deacuteveloppeurs du logiciel the GIMP (the GNUImage Manipulation Program) qui comme son nom lindique est un logiciel de manipulation dimages rattacheacute auprojet GNU Au vu de limportance de cette boicircte agrave outils GTK+ a eacuteteacute deacutetacheacute de the GIMP en septembre 1997Depuis il existe deux versions GTK+ 10 et GTK+ 20 versions qui ne sont pas totalement compatibles cependantla premiegravere est encore utiliseacutee dans certaines applications tel que dans le domaine de lembarqueacute du fait de sacomplexiteacute moindre Il est bien eacutevident que cest la seconde version qui est la plus utiliseacutee elle est agrave lorigine denombreux projets tel que le gestionnaire de fenecirctre GNOME (GNU Network Object Model Environment) La derniegravereversion en date est la 281 annonceacutee le 24 Aoucirct 2005

I-C-2 - Structure

Comme preacuteciseacute preacuteceacutedemment GTK+ est une boicircte agrave outils et en tant que tel elle est constitueacutee de plusieursbibliothegraveques indeacutependantes deacuteveloppeacutees par leacutequipe de GTK+

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 5 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

bull La GLib propose un ensemble de fonctions qui couvrent des domaines aussi vastes que les structures dedonneacutees la gestion des threads et des processus de faccedilon portable ou encore un analyseur syntaxique pourles fichiers XML et bien dautre

bull Pango il sagit de la bibliothegraveque daffichage et de rendue de textes

bull ATK

La bibliothegraveque GTK+ en elle-mecircme utilise une approche orienteacutee objet et repose sur plusieurs couches

bull GObject il sagit de la base de limpleacutementation des objets pour la POO

bull GDK bibliothegraveque graphique de bas niveau

bull GTK+ la bibliothegraveque GTK+ elle-mecircme baseacutee sur lutilisation de widgets (1)

Cest bien sucircr cette derniegravere qui nous inteacuteresse ici mais la glib nous sera aussi dune grande aide

I-C-3 - Pourquoi utiliser GTK+

Effectivement pourquoi choisir dutiliser GTK+ plutocirct quune autre bibliothegraveque pour reacutealiser une interface graphiqueVoici quelques arguments

bull GTK+ est sous licence libre LGPL vous pouvez donc lutiliser pour deacutevelopper des programmes libres oucommerciaux

bull La portabiliteacute GTK+ est disponible sur un grand nombre de systegravemes dont Windows Linux Unix et MacOSX

bull GTK+ est deacuteveloppeacutee en C et pour le langage C cependant elle est disponible pour dautres langages telsque Ada C++ (gracircce agrave gtkmm) Java Perl PHP Python Ruby ou plus reacutecemment C

I-D - Installation

I-D-1 - Windows

Pour pouvoir exeacutecuter une application utilisant GTK+ il faut commencer par installer les binaires Pour faciliter leurinstallation il existe un installeur

Si vous utilisez the Gimp utilisez les runtimes proposeacutees sur le sitehttpwwwgimp-winorg

Pour deacutevelopper une application il faut les bibliothegraveques ainsi que les fichiers den-tecircte disponibles sur gtkorg Pourceux qui utilisent CodeBlocks voici la meacutethode agrave suivre Installation de

I-D-2 - Linux

Sous Linux vous disposez sucircrement dun systegraveme de paquets Il vous faudra installer deux paquets le premiercontenant les fichiers permettant dexeacutecuter des programmes utilisant GTK+ le second paquet contient les fichiersneacutecessaires au deacuteveloppement

Une fois linstallation reacuteussie compilez agrave laide de la commande

gcc -Werror -Wall -W -O2 -ansi -pedantic `pkg-config --cflags --libs gtk+-20` c

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 6 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Tous les codes de ce tutoriel ont eacuteteacute testeacutes sous Linux Debian et Windows XP avecCodeBlocks

I-E - La philosophie GTK+

Voici quelques choix qui ont eacuteteacute faits par leacutequipe de deacuteveloppement de GTK+

bull Les noms de fonctions sont de la forme gtk_type_du_widget_action ceci rend les noms des fonctions tregravesexplicites en contre partie ils peuvent ecirctre tregraves longs

bull Tous les objets manipuleacutes sont des GtkWidget pour que GTK+ veacuterifie quil sagit du bon type dobjet lors delappel agrave une fonction chaque type de widget possegravede une macro de la forme GTK_TYPE_DU_WIDGET agraveutiliser pour transtyper vos widgets

bull La gestion des eacuteveacutenements qui modifient le comportement de lapplication (clique de souris pression dunetouche du clavier) se fait gracircce agrave lutilisation de fonctions de rappel (callback) Pour cela on connecte leswidgets agrave des fonctions qui seront appeleacutees lorsque leacuteveacutenement survient

I-F - Quelques notions de POO

La POO ou Programmation Orienteacutee Objet est un mode de programmation baseacutee sur des objets GTK+ utilisant ceprincipe (2) je vais vous en expliquer les principes de bases

Plutocirct que le deacuteroulement du programme soit reacutegie par une suite dinstruction en POO il est reacutegi par la creacuteationlinteraction et la destruction dobjets en reacutesumeacute la vie des objets qui le composent Un objets est une entiteacute (leparallegravele avec la vie courante est simple un objet pourrait ecirctre un ordinateur) en C on pourrait se repreacutesenter unobjet comme une structure de donneacutees

Un objet est composeacute de proprieacuteteacutes (ce qui correspond agrave nos variables) et de meacutethodes (des fonctions) Pour creacuteerun objet on fait appel agrave son constructeur il sagit dune fonction qui a pour but de creacuteer et dinitialiser lobjet A la finde sa vie lobjet doit ecirctre deacutetruit cest le but du destructeur

Dans la vie courante on peut creacuteer des objets complexes agrave partir de briques de base il est possible de creacuteer denouveaux objets en se basant sur un ou plusieurs objets ce meacutecanisme est appeler heacuteritage (on parle dheacuteritagemultiple lorsquil met en jeu plusieurs objets parents) Lobjet ainsi obtenu heacuterite des proprieacuteteacutes et des meacutethodes deses parents tout en pouvant modifier leur comportement et creacuteer ses propres proprieacuteteacutes et meacutethodes

Lorsque lon souhaite creacuteer un patron pour de futures classes plutocirct que de creacuteer une classe de base qui ne serajamais instancieacutee il est possible de creacuteer une interface

Le dernier concept de POO qui va nous servir dans ce tutoriel est le polymorphisme Ceci permet agrave un objet (prenonspar exemple camion) de se comporter comme lun de ses parents (dans le cas du camion il peut ecirctre vu comme unveacutehicule au mecircme titre quune voiture) Ceci est aussi valable pour des classes impleacutementant la mecircme interface

Pour vous initier aux joies de la programmation orienteacutee objet en C je vous conseille le tutoriel de CGI POO en C

I-G - Notre premier programme

Un programme qui utilise GTK+ est un programme eacutecrit en C avant tout il contient donc le code de base de toutprogramme C

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 7 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

maincinclude ltstdlibhgt

int main (int argc char argv) return EXIT_SUCCESS

Pour pouvoir utiliser les fonctions de GTK+ il faut bien sucircr inclure le fichier den-tecircte correspondant

include ltgtkgtkhgt

La premiegravere chose agrave faire est dinitialiser la machinerie GTK+ gracircce agrave la fonction gtk_init

void gtk_init (int argc char argv)

Cette fonction reccediloit les arguments passeacutes en ligne de commande ceux qui sont speacutecifiques agrave GTK+ sont ensuiteretireacutes de la liste dougrave lutilisation des pointeurs

Ensuite il nous faut creacuteer tous les widgets dont nous avons besoin si neacutecessaire modifier leurs paramegravetres pardeacutefaut les connecter agrave des fonctions callback et ensuite demander leur affichage (tout ceci sera expliciteacute dans lasuite du tutoriel) Une fois la fenecirctre principale creacuteeacutee il suffit de lancer la boucle principale de GTK+

void gtk_main (void)

Cette fonction est une boucle sans fin (seule la fonction gtk_main_quit permet den sortir) qui se charge de geacuterer ledeacuteroulement de notre programme (affichage des widgets envoi de signaux)

Voici donc notre premier programme en CGTK+ qui ne fait rien

maincinclude ltstdlibhgtinclude ltgtkgtkhgt

int main (int argc char argv) Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application

Lancement de la boucle principale gtk_main() return EXIT_SUCCESS

En plus de ne rien faire notre programme ne peut ecirctre termineacute que de faccedilon brutale (Ctrl+C) puisque nous nappelonspas la fonction gtk_main_quit

I-H - Code source

chapitre1zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 8 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

II - Notre premiegravere fenecirctre

II-A - Aperccedilu

II-B - Creacuteation

La fenecirctre principale est repreacutesenteacutee par la classe GtkWindow

La creacuteation dune fenecirctre se fait simplement en appelant le constructeur de cette classe la fonction gtk_window_new

GtkWidget gtk_window_new (GtkWindowType type)

Le seul paramegravetre de cette fonction est le type de fenecirctre souhaiteacute Il ny a que deux possibiliteacutes

bull GTK_WINDOW_TOPLEVEL une fenecirctre classique (cest la base de notre application)

bull GTK_WINDOW_POPUP il sagit dune fenecirctre avec seulement lespace de travail (pas de bordure ni demenu systegraveme)

Cette fonction renvoie un pointeur sur une structure de type GtkWindow (transformer en GtkWidget gracircce aupolymorphisme) qui est lentiteacute qui va nous servir agrave manipuler notre fenecirctre

II-C - Affichage

Si vous essayez deacutecrire un code maintenant vous ne verrez rien pourquoi Tout simplement parce quil faut preacuteciseragrave GTK+ quil faut rendre notre fenecirctre visible gracircce agrave la fonction gtk_widget_show

void gtk_widget_show (GtkWidget widget)

Voici le code qui permet dafficher notre premiegravere fenecirctre

maincinclude ltstdlibhgtinclude ltgtkgtkhgt

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL)

Affichage de la fenetre principale gtk_widget_show (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 9 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Ceux qui se sont essayeacutes agrave la creacuteation dapplications graphiques avec lAPI Windows comprendront la simpliciteacutede ce code

II-D - Destruction

Dans lexemple preacuteceacutedent si vous avez essayeacute de terminer lapplication en fermant la fenecirctre (Alt+F4 ou en cliquantsur la petite croix) vous vous ecirctes peut-ecirctre aperccedilu que lapplication tournait encore en fond cest le mecircme problegravemeque pour le chapitre preacuteceacutedent on ne fait pas appel agrave gtk_main_quit Mais comment appeler cette fonction puisquequune fois gtk_main appeleacutee nous ne pouvons rien faire Cest lagrave quintervient le meacutecanisme des callback A chaqueeacuteveacutenement qui se produit la bibliothegraveque GObject produit un signal si nous souhaitons modifier le comportementpar deacutefaut du signal il suffit de connecter notre fonction callback agrave leacuteveacutenement souhaiteacute

define g_signal_connect(instance detailed_signal c_handler data)

Cette macro permet dintercepter leacuteveacutenement detailed_signal de lobjet instance gracircce agrave la fonction c_handler quidoit ecirctre du type GCallback

void (GCallback) (void)

Les fonctions callback peuvent bien sucircr recevoir des paramegravetres mais leur nature et leur nombre deacutependent ducontexte tout est geacutereacute par la bibliothegraveque GObject Le prototype le plus courant pour une fonction de rappel estle suivant

void callback (GtkWidget p_widget gpointer user_data)

Dont le premier paramegravetre est le widget qui a reccedilu le signal et le second correspond au paramegravetre data de la fonctiong_signal_connect qui nous permet de passer des informations aux fonctions callback Pour finir proprement notreapplication il suffit dintercepter le signal destroy de notre fenecirctre et dy assigner la fonction gtk_main_quit qui neprend pas dargument Voici donc notre premiegravere application fonctionnelle

maincinclude ltstdlibhgtinclude ltgtkgtkhgt

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (gtk_main_quit) NULL)

Affichage de la fenetre principale gtk_widget_show (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

Il est plus courant de creacuteer notre propre fonction de rappel pour quitter le programme ceci permet de libeacuterer lameacutemoire alloueacutee fermer les fichiers ouverts

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 10 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

maincinclude ltstdlibhgtinclude ltgtkgtkhgt

void cb_quit (GtkWidget gpointer)

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (cb_quit) NULL)

Affichage de la fenetre principale gtk_widget_show (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

void cb_quit (GtkWidget p_widget gpointer user_data) gtk_main_quit()

Parametres inutilises (void)p_widget (void)user_data

Le preacutefixe cb_ permet de diffeacuterencier les fonctions callback quil est preacutefeacuterable de regrouper dans un ou plusieursfichiers seacutepareacutes

A la fin de la fonction je transtype les paramegravetres inutiliseacutes pour eacuteviter que moncompilateur mindique des variables non utiliseacutees cest le problegraveme avec les fonctionscallback lAPI nous impose un prototype

II-E - Code source

chapitre2zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 11 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

III - Fermer notre fenecirctre gracircce aux boutons

III-A - Aperccedilu

III-B - Les boutons poussoir

Maintenant que notre programme se termine proprement il est plus convivial de proposer agrave lutilisateur un boutonpour quitter Pour creacuteer un bouton poussoir il existe plusieurs possibiliteacutes

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 premiegravere fonction creacutee un bouton qui peut servir pour contenir nimporte quel autre widget (label image) Si voussouhaitez creacuteer un bouton avec du texte dessus utilisez directement la seconde fonction qui prend en argument letexte agrave afficher Si vous souhaitez ajouter un raccourci clavier (accessible avec la touche Alt) la troisiegraveme fonctionpermet den speacutecifier un en faisant preacuteceacuteder une lettre (geacuteneacuteralement la premiegravere) dun underscore _ (si voussouhaitez afficher le caractegravere _ il faut en mettre deux) Enfin la derniegravere fonction permet dutiliser les Stock Itemsqui sont un ensemble deacuteleacutements preacutedeacutefinis par GTK+ pour les menus et barres doutils Le seul paramegravetre de cettefonction est le nom de leacuteleacutement et GTK+ se charge dafficher licocircne approprieacutee ainsi que le texte suivant la languechoisie et un raccourci

Cest bien sucircr cette derniegravere fonction que nous allons utiliser et ce le plus souvent possible Voici le code pour creacuteerun tel bouton

maincGtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_QUIT)

Pour obtenir tous les types de stocks items disponibles GtkStockItem

Bien sucircr comme pour la fenecirctre si lon veut voir quelque chose il faut demander agrave GTK+ dafficher notre widget

maincgtk_widget_show (p_button)

Mais pas seulement En effet il faut preacuteciser agrave GTK+ ougrave doit ecirctre afficheacute notre bouton Pour cela la classe GtkWindowest deacuteriveacutee de la classe GtkContainer qui est comme son nom le laisse penser un conteneur pour widget Pourajouter un widget il suffit de faire appel agrave la fonction gtk_container_add

void gtk_container_add (GtkContainer container GtkWidget widget)

Le premier paramegravetre de cette fonction est un GtkContainer or nous souhaitons passer notre fenecirctre qui est unGtkWidget pour ne pas avoir de problegravemes il faut utiliser le systegraveme de macro offert par GTK+ pour transtyper notreGtkWidget en GtkContainer (eh oui en C le polymorphisme a ses limites)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 12 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

maincgtk_container_add (GTK_CONTAINER (p_window) p_button)

Ce meacutecanisme de transtypage permet agrave GTK+ de veacuterifier que notre GtkWidget est bien compatible avec lutilisationque lon souhaite en faire En cas deacutechec GTK+ nous preacutevient en affichant un message dans la console

(gtk_boutonexe1044) Gtk-CRITICAL gtk_container_add assertion `GTK_IS_CONTAINER (container) failed

Pour finir il faut connecter notre bouton pour appeler notre fonction cb_quit lorsque lutilisateur clic dessus (ce quicorrespond agrave leacuteveacutenement clicked)

g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_quit) NULL)

Pour eacuteviter dappeler la fonction gtk_widget_show pour tous les widgets de notreapplication on peut se contenter dun seul appel agrave la fonction gtk_widget_show_all quipermet dafficher tous les widgets contenus dans celui passeacute agrave la fonction

maincinclude ltstdlibhgtinclude ltgtkgtkhgtinclude callbackh

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (cb_quit) NULL)

GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_QUIT) gtk_container_add (GTK_CONTAINER (p_window) p_button) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_quit) NULL)

Affichage de la fenetre principale gtk_widget_show_all (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

III-C - Code source

chapitre3zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 13 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IV - Comment afficher plusieurs widgets

IV-A - Aperccedilu

IV-B - Le problegraveme

Dans la partie preacuteceacutedente nous avons reacuteussi agrave afficher un bouton dans la fenecirctre de notre application Si vous avezessayeacute dajouter un second widget GTK+ agrave ducirc vous reacutepondre poliment

(gtk_boxexe492) Gtk-WARNING Attempting to add a widget with typeGtkButton to a GtkWindow but as a GtkBin subclass a GtkWindow can only containone widget at a time it already contains a widget of type GtkButton

Les plus anglophiles dentre vous auront compris que GTK+ naccepte pas lajout un second widget dans notre fenecirctretout simplement parce quil y en a deacutejagrave un et que la sous classe GtkBin (classe megravere de notre GtkWindow) ne peutcontenir quun seul widget

IV-C - La solutions

Pour contourner ce problegraveme il faut commencer par creacuteer un widget qui accepte den contenir plusieurs autrespour ensuite y ajouter tout ce dont nous avons besoin Pour linstant nous utiliserons quun seul widget (il existetrois classes qui permettent ceci) il sagit des GtkBox Il sagit de la meacutethode que jutilise le plus souvent Ce nestpeut-ecirctre pas la plus simple agrave maicirctriser mais elle extrecircmement souple et puissante Elle consiste agrave creacuteer une boicirctepuis agrave y ajouter les widgets les uns apregraves les autres (soit au deacutebut soit agrave la fin) Il existe deux classes heacuteritant deGtkBox les GtkVBox qui empilent les widgets dans le sens vertical et les GtkHBox qui font de mecircme mais dansle sens horizontal Les fonctions pour manipuler ces deux classes sont les mecircmes seule la fonction pour les creacuteerportent un nom diffeacuterent

GtkWidget gtk_vbox_new (gboolean homogeneous gint spacing)GtkWidget gtk_hbox_new (gboolean homogeneous gint spacing)

Le paramegravetre homogeneous permet de reacuteserver pour chaque widget une zone de taille identique (zone que le widgetnest pas obligeacute de remplir) et spacing permet dajouter une bordure en pixels (espacement autour de la GtkBox)Ensuite il suffit dajouter les diffeacuterents widgets gracircce aux fonctions

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)

Qui ajoutent reacuteciproquement le widget child au deacutebut et agrave la fin de box Le paramegravetre expand permet au widget davoirle plus de place possible (si le paramegravetre homogeneous vaut TRUE cette option a aucun effet) Si plusieurs widgetont ce paramegravetre agrave TRUE ils se partagent de faccedilon eacutegale lespace Loption fill permet au widget de remplir toutlespace qui lui ait reacuteserveacute

Pour reacuteellement comprendre linfluence de ces paramegravetres il faut faire des tests en modifiant un agrave un chaqueparamegravetre et observer les effets dun redimentionnement de la fenecirctre principale

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 14 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Le plus gecircnant avec cette meacutethode cest quil faut jongler entre les GtkHBox et les GtkVBox en les imbriquant pourobtenir le reacutesultat souhaiter nheacutesitez pas agrave utiliser une feuille et un crayon )

Pour en revenir agrave notre eacutediteur de texte nous allons preacuteparer notre application agrave contenir les futurs widgetsNous utilisons un GtkVBox pour lensemble des widgets (il sagit de la boicircte principale qui pourra contenir dautresGtkContainer selon nos besoins)

maincinclude ltstdlibhgtinclude ltgtkgtkhgtinclude callbackh

int main (int argc char argv) GtkWidget p_window = NULL GtkWidget p_main_box = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (cb_quit) NULL)

Creation du conteneur principal p_main_box = gtk_vbox_new (FALSE 0) gtk_container_add (GTK_CONTAINER (p_window) p_main_box)

Creation du bouton Quitter GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_QUIT) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_quit) NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_button FALSE FALSE 0)

Affichage de la fenetre principale gtk_widget_show_all (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

IV-D - Code source

chapitre4zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 15 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

V - Afficher le contenue dun fichier

V-A - Aperccedilu

Cliquez pour agrandir

V-B - Saisir du texte

Les choses seacuterieuses vont commencer il sagit de mettre en place le widget qui va nous permettre dafficher etdeacutediter du texte Il sagit de la classe GtkTextView Gracircce agrave GTK+ la mise en place est toujours aussi simple

mainc GtkWidget p_text_view = NULL Creation de la zone de texte p_text_view = gtk_text_view_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_text_view TRUE TRUE 0)

Comme il sagit de la partie centrale de notre application nous demandons agrave ce quelle prenne le plus de placepossible (gracircce agrave la fonction gtk_box_pack_start)

Puisque nous voulons afficher les boutons en dessous de la zone de texte il faut ajouter ce morceau de code avantcelui creacuteant le bouton

V-C - Ouvrir un fichier

Maintenant nous avons une belle zone de texte il faut la remplir avec le contenu dun fichier Pour ce faire nousallons commencer par ajouter un bouton ouvrir

mainc Creation du bouton Ouvrir GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_OPEN) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_open) p_text_view) gtk_box_pack_start (GTK_BOX (p_main_box) p_button FALSE FALSE 0)

Si vous exeacutecutez le programme maintenant (3) vous remarquerez que les boutons sont ajouteacutes les uns en dessousdes autres ce qui diminue la zone de saisie (avec deux boutons ce nest pas gecircnant mais au bout dune dizaineccedila risque decirctre probleacutematique) Pour pallier ce problegraveme nous allons utiliser un nouveau style de GtkBox lesGtkButtonBox qui sont preacutevus pour contenir des boutons (ccedila tombe plutocirct bien D) Donc pour eacuteviter de diminuerla zone de saisie et comme nous avons de la place en largueur nous allons utiliser un GtkHButtonBox qui va ecirctreinclus dans la p_main_box Voici les modifications agrave effectuer

mainc GtkWidget p_button_box = NULL Creation du conteneur pour les boutons p_button_box = gtk_hbutton_box_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_button_box FALSE FALSE 0)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 16 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc gtk_box_pack_start (GTK_BOX (p_button_box) p_button FALSE FALSE 0) gtk_box_pack_start (GTK_BOX (p_button_box) p_button FALSE FALSE 0)

Maintenant il nous reste plus quagrave creacuteer la fonction cb_open dans le fichier callbackc pour linstant nous nouscontenterons douvrir toujours le mecircme fichier nous verrons plus tard comment laisser le choix agrave lutilisateur

callbackcdefine DEFAULT_FILE mainc

void cb_open (GtkWidget p_widget gpointer user_data) open_file (DEFAULT_FILE GTK_TEXT_VIEW (user_data))

Parametre inutilise (void)p_widget

Vous aurez compris que lon va deacuteleacuteguer tout le travail agrave la fonction open_file qui devra ouvrir le fichier dont le nomest passeacute en premier paramegravetre pour lafficher dans le GktTextView

Jai fait ce choix pour deux raisons le code dune fonction callback peut ecirctre tregraves conseacutequent (surtout si lon souhaitequelle affiche une boicircte de dialogue) et aussi parce que cb_open nest peut ecirctre pas la seule fonction agrave copierun fichier dans un GtkTextView (par exemple lors de la creacuteation dun nouveau fichier lon peut vouloir copier unsquelette de fichier)

Pour copier notre fichier plutocirct que dutiliser la fonction fgets nous allons nous servir de la glib (4) qui proposela fonction

gboolean g_file_get_contents (const gchar filename gchar contents gsize length GError error)

Qui nous renvoit le contenu du fichier nommeacute filename dans le tampon contents Il est possible de reacutecupeacuterer lenombre de caractegraveres copieacutes et retourne TRUE en cas de succegraves sinon FALSE et dans ce cas une structure de typeGError est creacutee pour en savoir plus sur le type derreur rencontreacute

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView else print_warning (Impossible douvrir le fichier sn file_name)

Je pense quun certain nombre dexplications simpose (surtout si je vais trop vite nheacutesitez pas agrave marrecircter )

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 17 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

bull g_return_if_fail est une macro qui peut ecirctre compareacutee agrave assert sauf quelle se contente de sortir de la fonctionsi lexpression passeacutee en paramegravetre est fausse Cest une meacutethode pratique pour veacuterifier la validiteacute desparamegravetres (si la fonction doit retourne une valeur utiliseacute plutocirct g_return_val_if_fail qui prend un secondparamegravetre la valeur agrave retourner)

bull Ensuite on essaie de reacutecupeacuterer le contenu de notre fichier

bull Si cela eacutechoue nous le signalons agrave lutilisateur agrave laide de la fonction print_warning

bull Le type gchar est une redeacutefinition du type char par la glib (il en va de mecircme pour tous les autres types du C)privileacutegiez ces types lorsque vous utilisez des fonctions de cette bibliothegraveques

Mais quest-ce donc cette fonction print_warning Cest une fonction que nous allons creacuteer semblable agrave printf quisignalera agrave lutilisateur quune erreur non critique est survenue Comme nous navons pas encore abordeacute les boicirctesde dialogue pour afficher un message il sagira pour linstant dune simple redeacutefinition de printf Pendant que noussommes dans laffichage des messages nous allons aussi creacuteer deux fonctions print_info et print_error qui vontrespectivement afficher un message dinformation et un message derreur critique (ce qui entraicircne la terminaison duprogramme) tout ceci dans un nouveau fichier errorc

errorhifndef H_ERRORdefine H_ERROR

void print_info (char )void print_warning (char )void print_error (char )

endif not H_ERROR

errorcinclude ltstdarghgtinclude ltstdiohgtinclude ltstdlibhgtinclude errorh

void print_info (char format ) va_list va

va_start (va format) printf (Information ) vprintf (format va) printf (n)

void print_warning (char format ) va_list va

va_start (va format) fprintf (stderr Erreur ) vfprintf (stderr format va) fprintf (stderr n)

void print_error (char format ) va_list va

va_start (va format) fprintf (stderr Erreur fatale ) vfprintf (stderr format va) fprintf (stderr n) exit (EXIT_FAILURE)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 18 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

Pour en finir avec louverture dun fichier il nous reste agrave copier contents dans le GtkTextView En fait le GtkTextViewne gegravere que la forme pour modifier le contenu il faut passer par les GtkTextBuffer Commenccedilons donc par reacutecupeacutererce fameux GtkTextBuffer

callbackc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (p_text_view)

Et pour finir on utilise la fonction

void gtk_text_buffer_insert (GtkTextBuffer buffer GtkTextIter iter const gchar text gint len)

Reacutecapitulons buffer est le GtkTextBuffer que lon vient de reacutecupeacuterer text cest le texte agrave afficher et len la taille dece dernier (ou -1 sil sagit dune chaicircne de caractegraveres au sens du langage C)

Mais quest-ce donc ce GtkTextIter On peut voir cela comme un curseur virtuel qui indique la position agrave laquelleeffectuer linsertion de texte dans le GtkTextBuffer (5) Allons voir ce que la documentation peut nous apprendreagrave leur sujet (6)

typedef struct GtkTextIter is an opaque datatype ignore all these fields Initialize the iter with gtk_text_buffer_get_iter_ functions GtkTextIter

Voilagrave on a notre solution suffit de rechercher les fonctions commenccedilant par gtk_text_buffer_get_iter_ voici la liste

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)

La fonction gtk_text_buffer_get_iter_at_line fait parfaitement laffaire

callbackc GtkTextIter iter

gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1)

Cependant si vous ne voulez pas avoir de problegravemes avec le codage des caractegraveres il vaut mieux convertir le codagelocal vers utf8 Voici le reacutesultat final

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 19 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gchar utf8 = NULL GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_text_buffer_insert (p_text_buffer ampiter utf8 -1) g_free (utf8) utf8 = NULL

V-D - La petite touche finale

Pour finir cette laborieuse partie sur une petite touche estheacutetique nous allons demander agrave GTK+ de nous lancerlapplication en plein eacutecran Pour se faire il suffit dajouter lors de la creacuteation de la fenecirctre principale

maincgtk_window_maximize (GTK_WINDOW (p_window))

On peut mecircme se permettre une pointe dexcentriciteacute en modifiant le titre de notre fenecirctre

maincgtk_window_set_title (GTK_WINDOW (p_window) Editeur de texte en GTK+)

V-E - Code source

chapitre5zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 20 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VI - Choisir un fichier

VI-A - Aperccedilu

Cliquez pour agrandir

VI-B - Utilisation dun GtkFileChooserFile

Jusquagrave preacutesent lutilisateur navait pas le choix quant au fichier agrave ouvrir heureusement GTK+ vient agrave notre aide gracircceau widget GtkFileChooserFile qui est tout simplement une boicircte de dialogue qui propose agrave lutilisateur de seacutelectionnerun fichier dans son arborescence disque

Commenccedilons par creacuteer notre boicircte de dialogue dans la fonction cb_open

callbackcvoid cb_open (GtkWidget p_widget gpointer user_data) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Ouvrir un fichier NULL GTK_FILE_CHOOSER_ACTION_OPEN GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_OPEN GTK_RESPONSE_ACCEPT NULL)

Cette fonction neacutecessite le titre de la boicircte de dialogue une fenecirctre parente le type daction (ici on souhaite ouvrir unfichier GTK+ autorisera lutilisateur agrave seacutelectionner uniquement les fichiers existants) Pour finir il sagit dun couple devaleurs GTK_STOCK_ITEMGTK_STOCK_RESPONSE qui permet de creacuteer un bouton utilisant le stock ID speacutecifieacuteet lorsque celui-ci est cliqueacute la fonction servant agrave lancer la boicircte de dialogue retournera le reacuteponse ID correspondantIl existe une seacuterie de valeurs deacutefinies par GTK+ quil est conseilleacute dutiliser

typedef enum GTK returns this if a response widget has no response_id or if the dialog gets programmatically hidden or destroyed GTK_RESPONSE_NONE = -1

GTK wont return these unless you pass them in as the response for an action widget They are for your convenience GTK_RESPONSE_REJECT = -2 GTK_RESPONSE_ACCEPT = -3

If the dialog is deleted GTK_RESPONSE_DELETE_EVENT = -4

These are returned from GTK dialogs and you can also use them yourself if you like GTK_RESPONSE_OK = -5 GTK_RESPONSE_CANCEL = -6 GTK_RESPONSE_CLOSE = -7 GTK_RESPONSE_YES = -8

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 21 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GTK_RESPONSE_NO = -9 GTK_RESPONSE_APPLY = -10 GTK_RESPONSE_HELP = -11 GtkResponseType

Nous indiquons la fin des couples stock idreacuteponse id avec la valeur NULL

Une fois la boicircte de dialogue creacuteee on demande agrave GTK+ de lafficher gracircce agrave la fonction gtk_dialog_run puis onreacutecupegravere sa valeur de retour qui correspond au bouton cliqueacute par lutilisateur

callbackc if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

Ici ce qui nous inteacuteresse cest lorsque que lutilisateur clique sur le bouton ouvrir (donc gtk_dialog_run renvoieGTK_RESPONSE_ACCEPT) dans ce cas il nous suffit de reacutecupeacuterer le nom du fichier seacutelectionneacute puis de louvrir

callbackc gchar file_name = NULL

file_name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) open_file (file_name GTK_TEXT_VIEW (user_data)) g_free (file_name) file_name = NULL

Pour finir dans tous les cas on noublie pas de deacutetruire la boicircte de dialogue

callbackc gtk_widget_destroy (p_dialog)

Et voilagrave le travail lutilisateur peut ouvrir le fichier quil souhaite

VI-C - Code source

chapitre6zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 22 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VII - Interlude

Avant daller plus loin dans lameacutelioration de linterface de notre eacutediteur il est neacutecessaire de modifier sonfonctionnement interne (ne vous inquieacutetez je nai pas dit chambouler) en effet souvenez-vous dans lintroduction jaieacutevoqueacute la possibiliteacutes douvrir plusieurs documents gracircce agrave un systegraveme donglets Pour cela il faut sauvegarder lesproprieacuteteacutes de chaque document ouvert Pris agrave temps ce genre de modification nest pas trop lourde mais si nousattendons cela risque de devenir un vrai casse tecircte

Pour cela nous allons utiliser une structure de donneacutee pour chaque document ouvert qui devra garder en meacutemoirele chemin complet du fichier (ou NULL si le document nest pas encore sauvegarder) sil agrave eacutetait modifier depuis laderniegravere sauvegarde et le GtkTextView qui sert agrave son affichage Voici donc la structure qui va nous servir

documenthtypedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

Sachant que nous serons ameneacute agrave stocker plusieurs occurrences de cette structure il serait bon de reacutefleacutechir degravesmaintenant agrave la structure de donneacutee agrave utiliser pour les stocker La premiegravere ideacutee qui vient agrave lesprit est un tableaualloueacute dynamiquement cependant lutilisateur peut souhaiter fermer un document qui se trouve au milieu on estalors obligeacute de deacutecaler toutes les cellules en amont Dans ce cas il parait naturel dutiliser une liste chaicircneacutee Parchance la glib propose une bibliothegraveque de gestion des listes chaicircneacutees cela nous fera gagner du temps le momentvenu Pour linstant on se contente de creacuteer une structure de donneacutees qui contiendra tous les documents ouverts(stockeacutee dans une GList) et un pointeur sur le document actif (actuellement comme nous navons quun documentouvert en mecircme temps on manipulera uniquement ce pointeur)

documenthtypedef struct GList tous document_t actif docs_t

Maintenant se pose le problegraveme de savoir comment transmettre cette structure On pourrait se servir du paramegravetreuser_data preacutesent dans toutes les fonctions callback mais certaines fonctions utilise deacutejagrave ce paramegravetre (la fonctioncb_open par exemple) il faudrait creacuteer un champs suppleacutementaire dans notre structure documents_s Une solutionplus simple est de creacuteer une variable globale agrave lensemble du programme Ceux qui passe reacuteguliegraverement sur le forumC savent que cest fortement deacuteconseilleacute mais ici nous nous trouvons dans lune des rares exceptions agrave la regravegle Detoute faccedilon cela revient au mecircme que de passer ladresse de notre structure agrave toutes les fonctions callback Nousdeacutefinissons donc un nouveau fichier den-tecircte

documenthifndef H_DOCUMENTdefine H_DOCUMENT

include ltgtkgtkhgt

typedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 23 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

documenthtypedef struct GList tous document_t actif docs_t

extern docs_t docs

endif not H_DOCUMENT

Et dans le fichier mainc

maincinclude documenth

docs_t docs = NULL NULL

Pour linstant la seule fonction qui modifie leacutetat dun document est la fonction open_file il faut donc inclure documenthdans callbackc et modifier leacutegegraverement la fonction pour enregistrer le document ouvert

callbackc if (g_file_get_contents (file_name ampcontents NULL NULL)) Pour linstant il faut allouer la memoire par la suite on modifira simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = g_strdup (file_name) Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = p_text_view Le document vient detre ouvert il nest donc pas modifie docsactif-gtsauve = TRUE

Ne soyez pas choqueacute si je ne teste pas le retour de la fonction g_malloc pour veacuterifier quilnest pas NULL En effet cette derniegravere met fin agrave lapplication si lallocation eacutechoue

VII-A - Code source

chapitre7zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 24 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VIII - Sauvegarder les modification

VIII-A - Aperccedilu

Cliquez pour agrandir

VIII-B - Enregistrer

Avant de pouvoir sauvegarder un document il faut quil soit modifieacute Comment savoir que le contenu du fichier a eacuteteacutemodifier Gracircce au signal changed du GtkTextBuffer que nous interceptons gracircce agrave la fonction cb_modifie

mainc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (p_text_view)) g_signal_connect (G_OBJECT (p_text_buffer) changed G_CALLBACK (cb_modifie) NULL)

Cette derniegravere modifie simplement le champ sauve du document

callbackcvoid cb_modifie (GtkWidget p_widget gpointer user_data) if (docsactif) docsactif-gtsauve = FALSE

Pour la sauvegarde il faut distinguer deux cas soit il sagit de la premiegravere sauvegarde du fichier il faut alors demanderle nom du fichier agrave lutilisateur (cela ressemble fortement agrave louverture dun fichier) soit le fichier est deacutejagrave preacutesent surle disque il suffit de remplacer son contenu par celui du GtkTextViewer Nous avons convenu quun fichier qui neacutetaitpas encore enregistreacute avait sa proprieacuteteacute chemin agrave NULL

Bien sucircr cela na lieu que si un fichier est ouvert et quil a eacuteteacute modifieacute depuis sa derniegravere sauvegarde

callbackcvoid cb_save (GtkWidget p_widget gpointer user_data) if (docsactif) if (docsactif-gtsauve) Le fichier na pas encore ete enregistre if (docsactif-gtchemin) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Sauvegarder le fichier NULL GTK_FILE_CHOOSER_ACTION_SAVE GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_SAVE GTK_RESPONSE_ACCEPT NULL) if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 25 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc docsactif-gtchemin = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) gtk_widget_destroy (p_dialog) Soit le fichier a deja ete enregistre soit lutilisateur vient de nous fournir son nouvel enplacement on peut donc lenregistrer if (docsactif-gtchemin) else print_warning (Aucun document ouvert)

Il nous reste plus quagrave reacutecupeacuterer le contenu du GtkTextViewer et le copier dans le fichier chemin sans oublier dereconvertir le texte dans le codage local

callbackc FILE fichier = NULL

fichier = fopen (docsactif-gtchemin w) if (fichier) gchar contents = NULL gchar locale = NULL GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) contents = gtk_text_buffer_get_text (p_text_buffer ampstart ampend FALSE) locale = g_locale_from_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL fprintf (fichier s locale) g_free (locale) locale = NULL fclose (fichier) fichier = NULL docsactif-gtsauve = TRUE else print_warning (Impossible de sauvegarder le fichier s docsactif-gtchemin)

Le dernier paramegravetre de la fonction gtk_text_buffer_get_text est mis agrave FALSE car nous ne voulons pas enregistrerles caractegraveres invisibles preacutesent dans le GtkTextBuffer Ces caractegraveres servent agrave mettre en forme le texte (taillecouleur) nous pourrions creacuteer un nouveau format de fichier pour enregistrer la mise en forme

VIII-C - Enregistrer sous

Pour enregistrer notre document sous un autre nom il suffit de faire croire agrave cb_save que le document na pas encoreeacutetait enregistreacute tout simplement en changeant chemin agrave NULL et sauve agrave FALSE

callbackcvoid cb_saveas (GtkWidget p_widget gpointer user_data)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 26 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (docsactif) document_t tmp = docsactif

docsactif-gtchemin = NULL docsactif-gtsauve = FALSE cb_save (p_widget user_data) if (docsactif-gtsauve) (docsactif) = tmp else print_warning (Aucun document ouvert)

Il ne faut pas oublier que lutilisateur peut annuler lenregistrement de ce fait nous sauvegardons leacutetat du documentet si la sauvegarde na pas eu lieu on le restaure

VIII-D - Code source

chapitre8zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 27 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IX - Creacuteer un nouveau document

IX-A - Aperccedilu

Cliquez pour agrandir

IX-B - Nouveau fichier

Maintenant que lutilisateur peut ouvrir et fermer un fichier il est inteacuteressant de lui donner la possibiliteacute den creacuteerun nouveau Je ne reviens pas sur la creacuteation du bouton (ccedila devrait deacutejagrave ecirctre fait D) passons directement agrave lafonction cb_new

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) Pour linstant il faut allouer la memoire par la suite on modifiera simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = NULL Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = GTK_TEXT_VIEW (user_data) Le document vient detre creer il nest donc pas modifie docsactif-gtsauve = TRUE gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Je ne sais pas vous mais pour ma part jai fait un copiercoller de la fonction open_file Et oui ouvrir un document peutse reacutesumer agrave creacuteer un document vide puis remplir le GtkTextView avec le fichier souhaiteacute On peut donc simplifiernotre fonction open_file ainsi

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

cb_new (NULL p_text_view) gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE) p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1) Nous sommes obliges de remetre sauve a TRUE car linsertion du contenu du fichier dans le GtkTextView a appele cb_modfie docsactif-gtsauve = TRUE else print_warning (Impossible douvrir le fichier sn file_name)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 28 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc

Cest beau la factorisation du code Par contre nous sommes obligeacutes de remettre sauve agrave TRUE car nous avonsmodifieacute le GtkTextBuffer

IX-C - Code source

chapitre9zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 29 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

X - Fermer

X-A - Aperccedilu

Cliquez pour agrandir

X-B - Fermer un fichier

Maintenant que nous allouons de la meacutemoire il faut la libeacuterer agrave un endroit Logiquement cela va ecirctre fait agrave la fermeturedu document en guise dexercice je vous laisse creacuteer le bouton dans notre boicircte agrave bouton

Allez je vous aide le stock id correspondant est GTK_STOCK_CLOSE

Voilagrave maintenant si tout cest bien passeacute vous devriez ecirctre arriveacute dans le fichier callbackc avec quelque choseressemblant agrave

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data)

Lorsque lon ferme un document il faut vider le GtkTextView (avec les onglets on se contentera de le supprimer)pour cela il faut reacutecupeacuterer le deacutebut et la fin du GtkTextBuffer et demander agrave GTK+ de supprimer tout ce qui ce trouveentre les deux iteacuterateurs

callbackc Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) gtk_text_buffer_delete (p_text_buffer ampstart ampend) else print_warning (Aucun document ouvert)

Bien sucircr il ne faut pas oublier de libeacuterer la meacutemoire

callbackc g_free (docsactif-gtchemin) docsactif-gtchemin = NULL docsactif-gtp_text_view = NULL g_free (docsactif) docsactif = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 30 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour symboliser la fermeture dun document nous deacutesactivons le GtkTextView lors de la fermeture (ne pas oublierde le faire aussi dans mainc)

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) FALSE)

Et nous le reacuteactivons lors de louverture si celle si reacuteussie

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Lorsque lutilisateur quitte lapplication il faut bien sucircr fermer le document sil y en a un ouvert

void cb_quit (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data) gtk_main_quit()

Et aussi lorsquil creacuteeacute un nouveau document (et par conseacutequent lorsquil ouvre un fichier puisque lon fait appel agravecb_new)

void cb_new (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data)

X-C - Enregistrer avant de fermer

Si le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde geacuteneacuteralement le programme le signale agrave lutilisateur etlui propose de sauvegarder ou dannuler la fermeture Pour se faire nous devons modifier la fonction cb_close avantde fermer le document nous allons afficher une boicircte de dialogue

Pour creacuteer une boicircte de dialogue simplement il existe la classe GtkDialog et comme nous avons besoin de boutons(pour que lutilisateur fasse son choix) nous allons creacuteer notre boicircte avec la fonction

GtkWidget gtk_dialog_new_with_buttons (const gchar title GtkWindow parent GtkDialogFlags flags const gchar first_button_text )

Nous retrouvons les mecircmes options que pour le GtkFileChooserDialog mis agrave part option du type GtkDialogFlags

typedef enum GTK_DIALOG_MODAL = 1 ltlt 0 appel gtk_window_set_modal (win TRUE) GTK_DIALOG_DESTROY_WITH_PARENT = 1 ltlt 1 appel gtk_window_set_destroy_with_parent () GTK_DIALOG_NO_SEPARATOR = 1 ltlt 2 Pas de barre de separation au dessus des boutons GtkDialogFlags

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 31 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Nous nous contenterons de rendre notre fenecirctre modale (7)

Pour avoir accegraves agrave notre fenecirctre principale nous ajoutons un champs p_main_window agrave notre structure globaledocs_t que nous initialisons dans la fonction main

mainc docsp_main_window = GTK_WINDOW (p_window)

Il nous reste plus qua creacuteer notre boicircte de dialogue avec trois boutons Oui Non Annuler

callbackc if (docsactif-gtsauve) GtkWidget p_dialog = NULL

p_dialog = gtk_dialog_new_with_buttons (Sauvegarder docsp_main_window GTK_DIALOG_MODAL GTK_STOCK_YES GTK_RESPONSE_YES GTK_STOCK_NO GTK_RESPONSE_NO GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL NULL)

Nous obtenons donc une structure de type GtkDialog

typedef struct GtkWidget vbox GtkWidget action_area GtkDialog

Nous remarquons que cette structure contient deux membres qui permettent dacceacuteder agrave une GtkBox ougrave nous allonsajouter le contenu de la fenecirctre et agrave la partie contenant les boutons

Ensuite la construction de la fenecirctre est identique agrave celle de la fenecirctre principale ici nous nous contenterons dajouterun GtkLabel

callbackc GtkWidget p_label = NULL p_label = gtk_label_new (Voulez-vous sauvegarder les modifications ) gtk_box_pack_start (GTK_BOX (GTK_DIALOG (p_dialog)-gtvbox) p_label TRUE TRUE 0)

Une fois notre fenecirctre precircte il suffit de faire appel agrave la fonction gtk_dialog_run qui va afficher notre GtkDialog et nousretourner le reacuteponse id correspondant au bouton cliqueacute par lutilisateur

callbackc switch (gtk_dialog_run (GTK_DIALOG (p_dialog))) case GTK_RESPONSE_YES cb_save (p_widget user_data) break case GTK_RESPONSE_NO break case GTK_RESPONSE_CANCEL gtk_widget_destroy (p_dialog) return break

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 32 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc gtk_widget_destroy (p_dialog)

Si lutilisateur clique sur non on ne fait rien (le document sera simplement fermeacute) sur oui on enregistre avant defermer et pour finir sil annule on quitte la fonction

X-D - Code source

chapitre10zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 33 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XI - Les barres de deacutefilement

XI-A - Aperccedilu

Cliquez pour agrandir

XI-B - Ajouter des barres de deacutefilement

Apregraves le dernier chapitre quelque peu laborieux voici une partie plus simple mais qui va rendre notre applicationplus pratique En effet si vous avez essayeacute douvrir un fichier de grande taille vous avez pu remarquer que pourpouvoir lire la fin du fichier il fallait utiliser les touches du clavier pas tregraves convivial

Pour rendre la navigation plus aiseacutee on utilise des barres de deacutefilement

mainc GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_scrolled_window TRUE TRUE 0)

Creation de la zone de texte gtk_container_add (GTK_CONTAINER (p_scrolled_window) p_text_view)

Le constructeur de notre GtkScrolledWindow prend en argument deux GtkAdjustment qui permettent de deacutefinirdiffeacuterentes proprieacuteteacutes de la barre de deacutefilement (taille dune page la position de deacutepart) nous laissons GTK+ faireen passant NULL

Cest un bon deacutebut mais estheacutetiquement on peut faire mieux mecircme sil nest pas utile davoir une barre de deacutefilementelle est quand mecircme afficheacutee On peut demander agrave GTK+ de les afficher que si cela est neacutecessaire

mainc gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC)

En fait nous avons de la chance car la classe GtkTextView fait partie des widget qui supporte de faccedilon native les barresde deacutefilement Comment le savoir Ce genre de widget possegravede une ou deux proprieacuteteacutes de type GtkAdjustment (unepour la barre verticale lautre pour la barre horizontale) Actuellement seulement trois classes en sont capables lesGtkTextView les GtkTreeView et les GtkLayout

Comment faire pour les autres widgets Il faut passer par une classe adaptateur GtkViewport afin de creacuteer lesGtkAdjustment

XI-C - Code source

chapitre11zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 34 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XII - Les menus

XII-A - Aperccedilu

Cliquez pour agrandir

XII-B - Creacuteation du menu

Pour simplifier nous avons utiliseacute des boutons pour permettre agrave lutilisateur de creacuteer un document ouvrir un fichierMais il est plus courant dutiliser un menu pour afficher ces options GTK+ propose trois maniegraveres de creacuteer un menu

bull GtkItemFactory cette meacutethode est obsolegravete depuis la version 24 de GTK+

bull GtkUIManager cest ce quon appel une usine agrave gaz pour en savoir plus vous pouvez vous reporter aututoriel Utilisation de GtkUIManager

bull GtkMenu cest ce widget que nous allons eacutetudier il permet de creacuteer un menu manuellement (agrave lopposeacute deGtkUIManager)

Un menu selon GTK+ est composeacute de plusieurs eacuteleacutements

bull GtkMenuBar la barre de menu elle-mecircme

bull GtkMenu la partie deacuteroulante qui contient les diffeacuterents eacuteleacutements

bull GtkMenuItem cest sur ce widget que lutilisateur clique pour lancer une action

Pour commencer faisons linventaire de ce que nous avons besoin

bull Un GtkMenuBar qui sert de base au menu

bull Un GtkMenu pour commencer nous nous aurons dun menu Fichier

bull Six GtkMenuItem pour remplacer nos six boutons

Commenccedilons par la creacuteation du menu nous mettons ce code dans un nouveau fichier dont seul la fonction menu_newsera accessible

menucGtkMenuBar menu_new (gpointer user_data) GtkWidget p_menu_bar = NULL

p_menu_bar = gtk_menu_bar_new () return GTK_MENU_BAR (p_menu_bar)

Le paramegravetre user_data nous servira lors de la connexion des callbacks (nous en avons besoin pour les fonctionscb_new et cb_open)

Ensuite nous allons creacuteer notre sous menu Fichier

menuc Menu Fichier

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 35 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

menuc GtkWidget p_menu = NULL GtkWidget p_menu_item = NULL

p_menu = gtk_menu_new () p_menu_item = gtk_menu_item_new_with_mnemonic (_Fichier) gtk_menu_item_set_submenu (GTK_MENU_ITEM (p_menu_item) p_menu) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu_bar) p_menu_item) return GTK_MENU_BAR (p_menu_bar)

Un sous menu est en fait un GtkMenuItem auquel on assigne un GtkMenu Il faut bien sucircr terminer la creacuteation dusous-menu en lajoutant agrave la barre de menu

Pour finir nous creacuteons les eacuteleacutements du menu les GtkItemMenu Il existe plusieurs types deacuteleacutements (comparableaux diffeacuterents types de bouton) pour commencer nous nutiliserons que le type de base Comme cette opeacuteration estreacutepeacutetitive nous allons creacuteer une fonction pour le faire

menucstatic void menu_item_new (GtkMenu p_menu const gchar title GCallback callback gpointer user_data) GtkWidget p_menu_item = NULL

p_menu_item = gtk_menu_item_new_with_mnemonic (title) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu) p_menu_item) g_signal_connect (G_OBJECT (p_menu_item) activate callback user_data)

Pour permettre agrave lutilisateur dacceacuteder aux diffeacuterents eacuteleacutements du menu agrave laide de la touche ltAltgt nous utilisonsdes mneacutemoniques par exemple pour quitter leacutediteur il suffit de faite Alt+F puis Q Et voici le code pour creacuteer nossix eacuteleacutements du menu

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau G_CALLBACK (cb_new) user_data) menu_item_new (GTK_MENU (p_menu) _Ouvrir G_CALLBACK (cb_open) user_data) menu_item_new (GTK_MENU (p_menu) _Enregistrer G_CALLBACK (cb_save) user_data) menu_item_new (GTK_MENU (p_menu) Enregistrer _sous G_CALLBACK (cb_saveas) user_data) menu_item_new (GTK_MENU (p_menu) _Fermer G_CALLBACK (cb_close) user_data) menu_item_new (GTK_MENU (p_menu) _Quitter G_CALLBACK (cb_quit) user_data)

Voilagrave notre menu est creacuteeacute il nous reste plus quagrave linteacutegrer agrave notre fenecirctre

mainc gtk_box_pack_start (GTK_BOX (p_main_box) GTK_WIDGET (menu_new (p_text_view)) FALSE FALSE 0)

Le problegraveme cest que nous avons besoin de passer le GtkTextView lors de la creacuteation du menu (qui est utiliseacute par lesfonctions cb_new et cb_open) or celui-ci est creacuteeacute apregraves le menu (puisque nous creacuteons les widgets dans lordre ougrave ilfaut les inteacutegrer agrave linterface (8) ) nous devons creacuteer le GtkTextView (seul lappel agrave gtk_text_view_new est deacuteplaceacute)

XII-C - Code source

chapitre12zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 36 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIII - Les barres doutils

XIII-A - Aperccedilu

Cliquez pour agrandir

XIII-B - Creacuteation dune barre doutils

La creacuteation dune barre doutils ressemble fort agrave celle dun menu en plus simple puisquil ny a pas de sous menu on creacutee notre barre doutils (gtk_toolbar_new) puis les eacuteleacutements de la barre pour cela on utilise des boutons(gtk_tool_button_new_from_stock) que lon inseacutere dans la barre (gtk_toolbar_insert) Pas conseacutequent notre fichierbarreoutilsc ressemble agrave menuc

barreoutilscinclude ltgtkgtkhgtinclude callbackhinclude barreoutilsh

static void toolbar_item_new (GtkToolbar const gchar GCallback gpointer)

GtkToolbar toolbar_new (gpointer user_data) GtkWidget p_toolbar = NULL

p_toolbar = gtk_toolbar_new () toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_NEW G_CALLBACK (cb_new) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_OPEN G_CALLBACK (cb_open) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE G_CALLBACK (cb_save) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE_AS G_CALLBACK (cb_saveas) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_CLOSE G_CALLBACK (cb_close) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_QUIT G_CALLBACK (cb_quit) user_data) return GTK_TOOLBAR (p_toolbar)

static void toolbar_item_new (GtkToolbar p_toolbar const gchar stock_id GCallback callback gpointer user_data) GtkToolItem p_tool_item = NULL

p_tool_item = gtk_tool_button_new_from_stock (stock_id) g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data) gtk_toolbar_insert (p_toolbar p_tool_item -1)

Le code nest pas complet car lorsque jexeacutecute le programme GTK+ affiche en plus des icocircnes le texte sous lesboutons Pour modifier cela il suffit dajouter une ligne de code

barreoutilsc gtk_toolbar_set_style (GTK_TOOLBAR (p_toolbar) GTK_TOOLBAR_ICONS)

Pourquoi gtk_tool_button_new_from_stock retourne un GtkToolItem et non un GtkWidgetcomme nous avons eacuteteacute habitueacute jusquagrave preacutesent Il sagit dune bizarrerie de GTK+ dontje ne connais pas la raison

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 37 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour anticiper un changement dinterface (dans GTK+ 30 peut ecirctre ) nous aurions pueacutecrire

Gtkwidget p_tool_item = NULL

p_tool_item = GTK_WIDGET (gtk_tool_button_new_from_stock (stock_id))g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data)gtk_toolbar_insert (p_toolbar GTK_TOOL_ITEM (p_tool_item) -1)

XIII-C - Code source

chapitre13zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 38 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIV - Les racourcis clavier

XIV-A - Aperccedilu

Cliquez pour agrandir

XIV-B - Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mneacutemoniques ces derniers permettent dacceacuteder agrave un eacuteleacutementseacutequentiellement alors que les raccourcis appellent une fonction si lutilisateur appuie simultaneacutement sur une ouplusieurs touches (geacuteneacuteralement de la forme ltModificateurgtTouche ougrave Modificateur repreacutesente les touches ShiftAlt et Control) Ce raccourci peut ecirctre attacheacute agrave un eacuteleacutement du menu mais ceci nest pas obligatoire

Les raccourcis sont regroupeacutes en groupe dans un GtkAccelGroup quil faut commencer par creacuteer

raccourciscinclude ltgtkgtkhgtinclude callbackhinclude raccourcish

GtkAccelGroup accel_group_new (gpointer user_data) GtkAccelGroup p_accel_group = NULL

p_accel_group = gtk_accel_group_new () return p_accel_group

Vous commencez agrave avoir lhabitude de cette organisation nous allons donc creacuteer une fonction qui va se chargerdajouter un raccourci au groupe

raccourciscstatic void accelerator_new (GtkAccelGroup p_accel_group const gchar accelerator const gchar accel_path GCallback callback gpointer user_data) guint key GdkModifierType mods GClosure closure = NULL

gtk_accelerator_parse (accelerator ampkey ampmods) closure = g_cclosure_new (callback user_data NULL) gtk_accel_group_connect (p_accel_group key mods GTK_ACCEL_VISIBLE closure) gtk_accel_map_add_entry (accel_path key mods)

La fonction gtk_accelerator_parse permet de deacutecomposer une chaicircne de caractegraveres de la forme ltControlgtF1 ouencore ltAltgtA en numeacutero de touche et modificateur

En plus des touches pour creacuteer un raccourci clavier nous avons besoin dune fonction agrave appeler lorsque lutilisateurappuie sur les touches speacutecifieacutees gtk_accel_group_connect attend une fonction du type GClosure regardons ladocumentation de gobject pour savoir agrave quoi cela correspond

typedef struct

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 2 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

I - IntroductionI-A - But de ce tutorielI-B - Connaissances requisesI-C - Quelques mots sur GTK+

I-C-1 - HistoriqueI-C-2 - StructureI-C-3 - Pourquoi utiliser GTK+

I-D - InstallationI-D-1 - WindowsI-D-2 - Linux

I-E - La philosophie GTK+I-F - Quelques notions de POOI-G - Notre premier programmeI-H - Code source

II - Notre premiegravere fenecirctreII-A - AperccediluII-B - CreacuteationII-C - AffichageII-D - DestructionII-E - Code source

III - Fermer notre fenecirctre gracircce aux boutonsIII-A - AperccediluIII-B - Les boutons poussoirIII-C - Code source

IV - Comment afficher plusieurs widgetsIV-A - AperccediluIV-B - Le problegravemeIV-C - La solutionsIV-D - Code source

V - Afficher le contenue dun fichierV-A - AperccediluV-B - Saisir du texteV-C - Ouvrir un fichierV-D - La petite touche finaleV-E - Code source

VI - Choisir un fichierVI-A - AperccediluVI-B - Utilisation dun GtkFileChooserFileVI-C - Code source

VII - InterludeVII-A - Code source

VIII - Sauvegarder les modificationVIII-A - AperccediluVIII-B - EnregistrerVIII-C - Enregistrer sousVIII-D - Code source

IX - Creacuteer un nouveau documentIX-A - AperccediluIX-B - Nouveau fichierIX-C - Code source

X - FermerX-A - AperccediluX-B - Fermer un fichierX-C - Enregistrer avant de fermer

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 3 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

X-D - Code sourceXI - Les barres de deacutefilement

XI-A - AperccediluXI-B - Ajouter des barres de deacutefilementXI-C - Code source

XII - Les menusXII-A - AperccediluXII-B - Creacuteation du menuXII-C - Code source

XIII - Les barres doutilsXIII-A - AperccediluXIII-B - Creacuteation dune barre doutilsXIII-C - Code source

XIV - Les racourcis clavierXIV-A - AperccediluXIV-B - Mise en place des raccourcis clavierXIV-C - Code source

XV - Messages derreurXV-A - AperccediluXV-B - Ameacutelioration de nos fonctions daffichage derreurXV-C - Code source

XVI - Ouvrir plusieurs fichiers en mecircme tempsXVI-A - AperccediluXVI-B - Mise en place des ongletsXVI-C - Changement de pageXVI-D - Fermer un ongletXVI-E - Fermer tous les ongletsXVI-F - Modifier le titre de la pageXVI-G - Code source

XVII - Afficher larborescence du disqueXVII-A - AperccediluXVII-B - Preacuteparons le terrainXVII-C - Creacuteation dun GtkTreeView

XVII-C-1 - Creacuteation du magasinXVII-C-2 - Affichage de larborescenceXVII-C-3 - Seacutelectionner un fichier

XVII-D - Code sourceXVIII - Notre signature

XVIII-A - AperccediluXVIII-B - Boicircte A proposXVIII-C - Code source

XIX - ConclusionXIX-A - Cest deacutejagrave fini XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 4 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

I - Introduction

I-A - But de ce tutoriel

Pour vous initier aux joies de la programmation dinterfaces graphiques plutocirct que de faire un catalogue de toutesles fonctions de la bibliothegraveque ce qui serait long et vite ennuyeux je vous propose de construire pas agrave pas uneapplication un eacutediteur de texte Pas un simple eacutediteur de texte histoire de faire le tour des possibiliteacutes de GTK+nous allons y ajouter pas agrave pas les fonctionnaliteacutes suivantes

bull Creacuteation ouverture enregistrement de fichiers textes

bull Possibiliteacute douvrir plusieurs fichiers gracircce agrave une navigation par onglets

bull Ouverture rapide dun fichier gracircce agrave une liste de fichiers

Rien dimpressionnant par rapport agrave un traitement de texte mais plus eacutevolueacute et plus pratique quun simple eacutediteurde texte Ce tutoriel est organiseacute de faccedilon agrave ajouter une nouvelle fonctionnaliteacute agrave chaque eacutetape tout en apprenantagrave maicirctriser un ou plusieurs eacuteleacutements de GTK+

Comme je viens de le dire il nest pas question de faire un catalogue de la bibliothegravequecependant avant dutiliser un nouveaux type de widget jen ferai une bregraveve descriptionqui pourra vous servir de pense becircte lors de vos futurs deacuteveloppements Cette descriptioncomportera un aperccedilu pour les widgets graphiques sa hieacuterarchie dheacuteritage ses fonctionsde creacuteations (constructeurs) les fonctions les plus utiliseacutees et les signaux importants dela classe

I-B - Connaissances requises

Le but de ce tutorial est dapprendre agrave maicirctriser GTK+ en partant de zeacutero ou presque en effet avant de vouloir creacuteerune interface graphique il vaut mieux bien connaicirctre le langage C en mode console Pour cela je vous renvoie aucours de la rubrique C

I-C - Quelques mots sur GTK+

I-C-1 - Historique

GTK+ ou the GIMP Toolkit eacutetait agrave lorigine une boicircte agrave outils pour les deacuteveloppeurs du logiciel the GIMP (the GNUImage Manipulation Program) qui comme son nom lindique est un logiciel de manipulation dimages rattacheacute auprojet GNU Au vu de limportance de cette boicircte agrave outils GTK+ a eacuteteacute deacutetacheacute de the GIMP en septembre 1997Depuis il existe deux versions GTK+ 10 et GTK+ 20 versions qui ne sont pas totalement compatibles cependantla premiegravere est encore utiliseacutee dans certaines applications tel que dans le domaine de lembarqueacute du fait de sacomplexiteacute moindre Il est bien eacutevident que cest la seconde version qui est la plus utiliseacutee elle est agrave lorigine denombreux projets tel que le gestionnaire de fenecirctre GNOME (GNU Network Object Model Environment) La derniegravereversion en date est la 281 annonceacutee le 24 Aoucirct 2005

I-C-2 - Structure

Comme preacuteciseacute preacuteceacutedemment GTK+ est une boicircte agrave outils et en tant que tel elle est constitueacutee de plusieursbibliothegraveques indeacutependantes deacuteveloppeacutees par leacutequipe de GTK+

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 5 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

bull La GLib propose un ensemble de fonctions qui couvrent des domaines aussi vastes que les structures dedonneacutees la gestion des threads et des processus de faccedilon portable ou encore un analyseur syntaxique pourles fichiers XML et bien dautre

bull Pango il sagit de la bibliothegraveque daffichage et de rendue de textes

bull ATK

La bibliothegraveque GTK+ en elle-mecircme utilise une approche orienteacutee objet et repose sur plusieurs couches

bull GObject il sagit de la base de limpleacutementation des objets pour la POO

bull GDK bibliothegraveque graphique de bas niveau

bull GTK+ la bibliothegraveque GTK+ elle-mecircme baseacutee sur lutilisation de widgets (1)

Cest bien sucircr cette derniegravere qui nous inteacuteresse ici mais la glib nous sera aussi dune grande aide

I-C-3 - Pourquoi utiliser GTK+

Effectivement pourquoi choisir dutiliser GTK+ plutocirct quune autre bibliothegraveque pour reacutealiser une interface graphiqueVoici quelques arguments

bull GTK+ est sous licence libre LGPL vous pouvez donc lutiliser pour deacutevelopper des programmes libres oucommerciaux

bull La portabiliteacute GTK+ est disponible sur un grand nombre de systegravemes dont Windows Linux Unix et MacOSX

bull GTK+ est deacuteveloppeacutee en C et pour le langage C cependant elle est disponible pour dautres langages telsque Ada C++ (gracircce agrave gtkmm) Java Perl PHP Python Ruby ou plus reacutecemment C

I-D - Installation

I-D-1 - Windows

Pour pouvoir exeacutecuter une application utilisant GTK+ il faut commencer par installer les binaires Pour faciliter leurinstallation il existe un installeur

Si vous utilisez the Gimp utilisez les runtimes proposeacutees sur le sitehttpwwwgimp-winorg

Pour deacutevelopper une application il faut les bibliothegraveques ainsi que les fichiers den-tecircte disponibles sur gtkorg Pourceux qui utilisent CodeBlocks voici la meacutethode agrave suivre Installation de

I-D-2 - Linux

Sous Linux vous disposez sucircrement dun systegraveme de paquets Il vous faudra installer deux paquets le premiercontenant les fichiers permettant dexeacutecuter des programmes utilisant GTK+ le second paquet contient les fichiersneacutecessaires au deacuteveloppement

Une fois linstallation reacuteussie compilez agrave laide de la commande

gcc -Werror -Wall -W -O2 -ansi -pedantic `pkg-config --cflags --libs gtk+-20` c

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 6 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Tous les codes de ce tutoriel ont eacuteteacute testeacutes sous Linux Debian et Windows XP avecCodeBlocks

I-E - La philosophie GTK+

Voici quelques choix qui ont eacuteteacute faits par leacutequipe de deacuteveloppement de GTK+

bull Les noms de fonctions sont de la forme gtk_type_du_widget_action ceci rend les noms des fonctions tregravesexplicites en contre partie ils peuvent ecirctre tregraves longs

bull Tous les objets manipuleacutes sont des GtkWidget pour que GTK+ veacuterifie quil sagit du bon type dobjet lors delappel agrave une fonction chaque type de widget possegravede une macro de la forme GTK_TYPE_DU_WIDGET agraveutiliser pour transtyper vos widgets

bull La gestion des eacuteveacutenements qui modifient le comportement de lapplication (clique de souris pression dunetouche du clavier) se fait gracircce agrave lutilisation de fonctions de rappel (callback) Pour cela on connecte leswidgets agrave des fonctions qui seront appeleacutees lorsque leacuteveacutenement survient

I-F - Quelques notions de POO

La POO ou Programmation Orienteacutee Objet est un mode de programmation baseacutee sur des objets GTK+ utilisant ceprincipe (2) je vais vous en expliquer les principes de bases

Plutocirct que le deacuteroulement du programme soit reacutegie par une suite dinstruction en POO il est reacutegi par la creacuteationlinteraction et la destruction dobjets en reacutesumeacute la vie des objets qui le composent Un objets est une entiteacute (leparallegravele avec la vie courante est simple un objet pourrait ecirctre un ordinateur) en C on pourrait se repreacutesenter unobjet comme une structure de donneacutees

Un objet est composeacute de proprieacuteteacutes (ce qui correspond agrave nos variables) et de meacutethodes (des fonctions) Pour creacuteerun objet on fait appel agrave son constructeur il sagit dune fonction qui a pour but de creacuteer et dinitialiser lobjet A la finde sa vie lobjet doit ecirctre deacutetruit cest le but du destructeur

Dans la vie courante on peut creacuteer des objets complexes agrave partir de briques de base il est possible de creacuteer denouveaux objets en se basant sur un ou plusieurs objets ce meacutecanisme est appeler heacuteritage (on parle dheacuteritagemultiple lorsquil met en jeu plusieurs objets parents) Lobjet ainsi obtenu heacuterite des proprieacuteteacutes et des meacutethodes deses parents tout en pouvant modifier leur comportement et creacuteer ses propres proprieacuteteacutes et meacutethodes

Lorsque lon souhaite creacuteer un patron pour de futures classes plutocirct que de creacuteer une classe de base qui ne serajamais instancieacutee il est possible de creacuteer une interface

Le dernier concept de POO qui va nous servir dans ce tutoriel est le polymorphisme Ceci permet agrave un objet (prenonspar exemple camion) de se comporter comme lun de ses parents (dans le cas du camion il peut ecirctre vu comme unveacutehicule au mecircme titre quune voiture) Ceci est aussi valable pour des classes impleacutementant la mecircme interface

Pour vous initier aux joies de la programmation orienteacutee objet en C je vous conseille le tutoriel de CGI POO en C

I-G - Notre premier programme

Un programme qui utilise GTK+ est un programme eacutecrit en C avant tout il contient donc le code de base de toutprogramme C

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 7 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

maincinclude ltstdlibhgt

int main (int argc char argv) return EXIT_SUCCESS

Pour pouvoir utiliser les fonctions de GTK+ il faut bien sucircr inclure le fichier den-tecircte correspondant

include ltgtkgtkhgt

La premiegravere chose agrave faire est dinitialiser la machinerie GTK+ gracircce agrave la fonction gtk_init

void gtk_init (int argc char argv)

Cette fonction reccediloit les arguments passeacutes en ligne de commande ceux qui sont speacutecifiques agrave GTK+ sont ensuiteretireacutes de la liste dougrave lutilisation des pointeurs

Ensuite il nous faut creacuteer tous les widgets dont nous avons besoin si neacutecessaire modifier leurs paramegravetres pardeacutefaut les connecter agrave des fonctions callback et ensuite demander leur affichage (tout ceci sera expliciteacute dans lasuite du tutoriel) Une fois la fenecirctre principale creacuteeacutee il suffit de lancer la boucle principale de GTK+

void gtk_main (void)

Cette fonction est une boucle sans fin (seule la fonction gtk_main_quit permet den sortir) qui se charge de geacuterer ledeacuteroulement de notre programme (affichage des widgets envoi de signaux)

Voici donc notre premier programme en CGTK+ qui ne fait rien

maincinclude ltstdlibhgtinclude ltgtkgtkhgt

int main (int argc char argv) Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application

Lancement de la boucle principale gtk_main() return EXIT_SUCCESS

En plus de ne rien faire notre programme ne peut ecirctre termineacute que de faccedilon brutale (Ctrl+C) puisque nous nappelonspas la fonction gtk_main_quit

I-H - Code source

chapitre1zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 8 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

II - Notre premiegravere fenecirctre

II-A - Aperccedilu

II-B - Creacuteation

La fenecirctre principale est repreacutesenteacutee par la classe GtkWindow

La creacuteation dune fenecirctre se fait simplement en appelant le constructeur de cette classe la fonction gtk_window_new

GtkWidget gtk_window_new (GtkWindowType type)

Le seul paramegravetre de cette fonction est le type de fenecirctre souhaiteacute Il ny a que deux possibiliteacutes

bull GTK_WINDOW_TOPLEVEL une fenecirctre classique (cest la base de notre application)

bull GTK_WINDOW_POPUP il sagit dune fenecirctre avec seulement lespace de travail (pas de bordure ni demenu systegraveme)

Cette fonction renvoie un pointeur sur une structure de type GtkWindow (transformer en GtkWidget gracircce aupolymorphisme) qui est lentiteacute qui va nous servir agrave manipuler notre fenecirctre

II-C - Affichage

Si vous essayez deacutecrire un code maintenant vous ne verrez rien pourquoi Tout simplement parce quil faut preacuteciseragrave GTK+ quil faut rendre notre fenecirctre visible gracircce agrave la fonction gtk_widget_show

void gtk_widget_show (GtkWidget widget)

Voici le code qui permet dafficher notre premiegravere fenecirctre

maincinclude ltstdlibhgtinclude ltgtkgtkhgt

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL)

Affichage de la fenetre principale gtk_widget_show (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 9 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Ceux qui se sont essayeacutes agrave la creacuteation dapplications graphiques avec lAPI Windows comprendront la simpliciteacutede ce code

II-D - Destruction

Dans lexemple preacuteceacutedent si vous avez essayeacute de terminer lapplication en fermant la fenecirctre (Alt+F4 ou en cliquantsur la petite croix) vous vous ecirctes peut-ecirctre aperccedilu que lapplication tournait encore en fond cest le mecircme problegravemeque pour le chapitre preacuteceacutedent on ne fait pas appel agrave gtk_main_quit Mais comment appeler cette fonction puisquequune fois gtk_main appeleacutee nous ne pouvons rien faire Cest lagrave quintervient le meacutecanisme des callback A chaqueeacuteveacutenement qui se produit la bibliothegraveque GObject produit un signal si nous souhaitons modifier le comportementpar deacutefaut du signal il suffit de connecter notre fonction callback agrave leacuteveacutenement souhaiteacute

define g_signal_connect(instance detailed_signal c_handler data)

Cette macro permet dintercepter leacuteveacutenement detailed_signal de lobjet instance gracircce agrave la fonction c_handler quidoit ecirctre du type GCallback

void (GCallback) (void)

Les fonctions callback peuvent bien sucircr recevoir des paramegravetres mais leur nature et leur nombre deacutependent ducontexte tout est geacutereacute par la bibliothegraveque GObject Le prototype le plus courant pour une fonction de rappel estle suivant

void callback (GtkWidget p_widget gpointer user_data)

Dont le premier paramegravetre est le widget qui a reccedilu le signal et le second correspond au paramegravetre data de la fonctiong_signal_connect qui nous permet de passer des informations aux fonctions callback Pour finir proprement notreapplication il suffit dintercepter le signal destroy de notre fenecirctre et dy assigner la fonction gtk_main_quit qui neprend pas dargument Voici donc notre premiegravere application fonctionnelle

maincinclude ltstdlibhgtinclude ltgtkgtkhgt

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (gtk_main_quit) NULL)

Affichage de la fenetre principale gtk_widget_show (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

Il est plus courant de creacuteer notre propre fonction de rappel pour quitter le programme ceci permet de libeacuterer lameacutemoire alloueacutee fermer les fichiers ouverts

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 10 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

maincinclude ltstdlibhgtinclude ltgtkgtkhgt

void cb_quit (GtkWidget gpointer)

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (cb_quit) NULL)

Affichage de la fenetre principale gtk_widget_show (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

void cb_quit (GtkWidget p_widget gpointer user_data) gtk_main_quit()

Parametres inutilises (void)p_widget (void)user_data

Le preacutefixe cb_ permet de diffeacuterencier les fonctions callback quil est preacutefeacuterable de regrouper dans un ou plusieursfichiers seacutepareacutes

A la fin de la fonction je transtype les paramegravetres inutiliseacutes pour eacuteviter que moncompilateur mindique des variables non utiliseacutees cest le problegraveme avec les fonctionscallback lAPI nous impose un prototype

II-E - Code source

chapitre2zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 11 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

III - Fermer notre fenecirctre gracircce aux boutons

III-A - Aperccedilu

III-B - Les boutons poussoir

Maintenant que notre programme se termine proprement il est plus convivial de proposer agrave lutilisateur un boutonpour quitter Pour creacuteer un bouton poussoir il existe plusieurs possibiliteacutes

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 premiegravere fonction creacutee un bouton qui peut servir pour contenir nimporte quel autre widget (label image) Si voussouhaitez creacuteer un bouton avec du texte dessus utilisez directement la seconde fonction qui prend en argument letexte agrave afficher Si vous souhaitez ajouter un raccourci clavier (accessible avec la touche Alt) la troisiegraveme fonctionpermet den speacutecifier un en faisant preacuteceacuteder une lettre (geacuteneacuteralement la premiegravere) dun underscore _ (si voussouhaitez afficher le caractegravere _ il faut en mettre deux) Enfin la derniegravere fonction permet dutiliser les Stock Itemsqui sont un ensemble deacuteleacutements preacutedeacutefinis par GTK+ pour les menus et barres doutils Le seul paramegravetre de cettefonction est le nom de leacuteleacutement et GTK+ se charge dafficher licocircne approprieacutee ainsi que le texte suivant la languechoisie et un raccourci

Cest bien sucircr cette derniegravere fonction que nous allons utiliser et ce le plus souvent possible Voici le code pour creacuteerun tel bouton

maincGtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_QUIT)

Pour obtenir tous les types de stocks items disponibles GtkStockItem

Bien sucircr comme pour la fenecirctre si lon veut voir quelque chose il faut demander agrave GTK+ dafficher notre widget

maincgtk_widget_show (p_button)

Mais pas seulement En effet il faut preacuteciser agrave GTK+ ougrave doit ecirctre afficheacute notre bouton Pour cela la classe GtkWindowest deacuteriveacutee de la classe GtkContainer qui est comme son nom le laisse penser un conteneur pour widget Pourajouter un widget il suffit de faire appel agrave la fonction gtk_container_add

void gtk_container_add (GtkContainer container GtkWidget widget)

Le premier paramegravetre de cette fonction est un GtkContainer or nous souhaitons passer notre fenecirctre qui est unGtkWidget pour ne pas avoir de problegravemes il faut utiliser le systegraveme de macro offert par GTK+ pour transtyper notreGtkWidget en GtkContainer (eh oui en C le polymorphisme a ses limites)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 12 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

maincgtk_container_add (GTK_CONTAINER (p_window) p_button)

Ce meacutecanisme de transtypage permet agrave GTK+ de veacuterifier que notre GtkWidget est bien compatible avec lutilisationque lon souhaite en faire En cas deacutechec GTK+ nous preacutevient en affichant un message dans la console

(gtk_boutonexe1044) Gtk-CRITICAL gtk_container_add assertion `GTK_IS_CONTAINER (container) failed

Pour finir il faut connecter notre bouton pour appeler notre fonction cb_quit lorsque lutilisateur clic dessus (ce quicorrespond agrave leacuteveacutenement clicked)

g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_quit) NULL)

Pour eacuteviter dappeler la fonction gtk_widget_show pour tous les widgets de notreapplication on peut se contenter dun seul appel agrave la fonction gtk_widget_show_all quipermet dafficher tous les widgets contenus dans celui passeacute agrave la fonction

maincinclude ltstdlibhgtinclude ltgtkgtkhgtinclude callbackh

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (cb_quit) NULL)

GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_QUIT) gtk_container_add (GTK_CONTAINER (p_window) p_button) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_quit) NULL)

Affichage de la fenetre principale gtk_widget_show_all (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

III-C - Code source

chapitre3zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 13 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IV - Comment afficher plusieurs widgets

IV-A - Aperccedilu

IV-B - Le problegraveme

Dans la partie preacuteceacutedente nous avons reacuteussi agrave afficher un bouton dans la fenecirctre de notre application Si vous avezessayeacute dajouter un second widget GTK+ agrave ducirc vous reacutepondre poliment

(gtk_boxexe492) Gtk-WARNING Attempting to add a widget with typeGtkButton to a GtkWindow but as a GtkBin subclass a GtkWindow can only containone widget at a time it already contains a widget of type GtkButton

Les plus anglophiles dentre vous auront compris que GTK+ naccepte pas lajout un second widget dans notre fenecirctretout simplement parce quil y en a deacutejagrave un et que la sous classe GtkBin (classe megravere de notre GtkWindow) ne peutcontenir quun seul widget

IV-C - La solutions

Pour contourner ce problegraveme il faut commencer par creacuteer un widget qui accepte den contenir plusieurs autrespour ensuite y ajouter tout ce dont nous avons besoin Pour linstant nous utiliserons quun seul widget (il existetrois classes qui permettent ceci) il sagit des GtkBox Il sagit de la meacutethode que jutilise le plus souvent Ce nestpeut-ecirctre pas la plus simple agrave maicirctriser mais elle extrecircmement souple et puissante Elle consiste agrave creacuteer une boicirctepuis agrave y ajouter les widgets les uns apregraves les autres (soit au deacutebut soit agrave la fin) Il existe deux classes heacuteritant deGtkBox les GtkVBox qui empilent les widgets dans le sens vertical et les GtkHBox qui font de mecircme mais dansle sens horizontal Les fonctions pour manipuler ces deux classes sont les mecircmes seule la fonction pour les creacuteerportent un nom diffeacuterent

GtkWidget gtk_vbox_new (gboolean homogeneous gint spacing)GtkWidget gtk_hbox_new (gboolean homogeneous gint spacing)

Le paramegravetre homogeneous permet de reacuteserver pour chaque widget une zone de taille identique (zone que le widgetnest pas obligeacute de remplir) et spacing permet dajouter une bordure en pixels (espacement autour de la GtkBox)Ensuite il suffit dajouter les diffeacuterents widgets gracircce aux fonctions

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)

Qui ajoutent reacuteciproquement le widget child au deacutebut et agrave la fin de box Le paramegravetre expand permet au widget davoirle plus de place possible (si le paramegravetre homogeneous vaut TRUE cette option a aucun effet) Si plusieurs widgetont ce paramegravetre agrave TRUE ils se partagent de faccedilon eacutegale lespace Loption fill permet au widget de remplir toutlespace qui lui ait reacuteserveacute

Pour reacuteellement comprendre linfluence de ces paramegravetres il faut faire des tests en modifiant un agrave un chaqueparamegravetre et observer les effets dun redimentionnement de la fenecirctre principale

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 14 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Le plus gecircnant avec cette meacutethode cest quil faut jongler entre les GtkHBox et les GtkVBox en les imbriquant pourobtenir le reacutesultat souhaiter nheacutesitez pas agrave utiliser une feuille et un crayon )

Pour en revenir agrave notre eacutediteur de texte nous allons preacuteparer notre application agrave contenir les futurs widgetsNous utilisons un GtkVBox pour lensemble des widgets (il sagit de la boicircte principale qui pourra contenir dautresGtkContainer selon nos besoins)

maincinclude ltstdlibhgtinclude ltgtkgtkhgtinclude callbackh

int main (int argc char argv) GtkWidget p_window = NULL GtkWidget p_main_box = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (cb_quit) NULL)

Creation du conteneur principal p_main_box = gtk_vbox_new (FALSE 0) gtk_container_add (GTK_CONTAINER (p_window) p_main_box)

Creation du bouton Quitter GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_QUIT) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_quit) NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_button FALSE FALSE 0)

Affichage de la fenetre principale gtk_widget_show_all (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

IV-D - Code source

chapitre4zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 15 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

V - Afficher le contenue dun fichier

V-A - Aperccedilu

Cliquez pour agrandir

V-B - Saisir du texte

Les choses seacuterieuses vont commencer il sagit de mettre en place le widget qui va nous permettre dafficher etdeacutediter du texte Il sagit de la classe GtkTextView Gracircce agrave GTK+ la mise en place est toujours aussi simple

mainc GtkWidget p_text_view = NULL Creation de la zone de texte p_text_view = gtk_text_view_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_text_view TRUE TRUE 0)

Comme il sagit de la partie centrale de notre application nous demandons agrave ce quelle prenne le plus de placepossible (gracircce agrave la fonction gtk_box_pack_start)

Puisque nous voulons afficher les boutons en dessous de la zone de texte il faut ajouter ce morceau de code avantcelui creacuteant le bouton

V-C - Ouvrir un fichier

Maintenant nous avons une belle zone de texte il faut la remplir avec le contenu dun fichier Pour ce faire nousallons commencer par ajouter un bouton ouvrir

mainc Creation du bouton Ouvrir GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_OPEN) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_open) p_text_view) gtk_box_pack_start (GTK_BOX (p_main_box) p_button FALSE FALSE 0)

Si vous exeacutecutez le programme maintenant (3) vous remarquerez que les boutons sont ajouteacutes les uns en dessousdes autres ce qui diminue la zone de saisie (avec deux boutons ce nest pas gecircnant mais au bout dune dizaineccedila risque decirctre probleacutematique) Pour pallier ce problegraveme nous allons utiliser un nouveau style de GtkBox lesGtkButtonBox qui sont preacutevus pour contenir des boutons (ccedila tombe plutocirct bien D) Donc pour eacuteviter de diminuerla zone de saisie et comme nous avons de la place en largueur nous allons utiliser un GtkHButtonBox qui va ecirctreinclus dans la p_main_box Voici les modifications agrave effectuer

mainc GtkWidget p_button_box = NULL Creation du conteneur pour les boutons p_button_box = gtk_hbutton_box_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_button_box FALSE FALSE 0)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 16 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc gtk_box_pack_start (GTK_BOX (p_button_box) p_button FALSE FALSE 0) gtk_box_pack_start (GTK_BOX (p_button_box) p_button FALSE FALSE 0)

Maintenant il nous reste plus quagrave creacuteer la fonction cb_open dans le fichier callbackc pour linstant nous nouscontenterons douvrir toujours le mecircme fichier nous verrons plus tard comment laisser le choix agrave lutilisateur

callbackcdefine DEFAULT_FILE mainc

void cb_open (GtkWidget p_widget gpointer user_data) open_file (DEFAULT_FILE GTK_TEXT_VIEW (user_data))

Parametre inutilise (void)p_widget

Vous aurez compris que lon va deacuteleacuteguer tout le travail agrave la fonction open_file qui devra ouvrir le fichier dont le nomest passeacute en premier paramegravetre pour lafficher dans le GktTextView

Jai fait ce choix pour deux raisons le code dune fonction callback peut ecirctre tregraves conseacutequent (surtout si lon souhaitequelle affiche une boicircte de dialogue) et aussi parce que cb_open nest peut ecirctre pas la seule fonction agrave copierun fichier dans un GtkTextView (par exemple lors de la creacuteation dun nouveau fichier lon peut vouloir copier unsquelette de fichier)

Pour copier notre fichier plutocirct que dutiliser la fonction fgets nous allons nous servir de la glib (4) qui proposela fonction

gboolean g_file_get_contents (const gchar filename gchar contents gsize length GError error)

Qui nous renvoit le contenu du fichier nommeacute filename dans le tampon contents Il est possible de reacutecupeacuterer lenombre de caractegraveres copieacutes et retourne TRUE en cas de succegraves sinon FALSE et dans ce cas une structure de typeGError est creacutee pour en savoir plus sur le type derreur rencontreacute

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView else print_warning (Impossible douvrir le fichier sn file_name)

Je pense quun certain nombre dexplications simpose (surtout si je vais trop vite nheacutesitez pas agrave marrecircter )

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 17 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

bull g_return_if_fail est une macro qui peut ecirctre compareacutee agrave assert sauf quelle se contente de sortir de la fonctionsi lexpression passeacutee en paramegravetre est fausse Cest une meacutethode pratique pour veacuterifier la validiteacute desparamegravetres (si la fonction doit retourne une valeur utiliseacute plutocirct g_return_val_if_fail qui prend un secondparamegravetre la valeur agrave retourner)

bull Ensuite on essaie de reacutecupeacuterer le contenu de notre fichier

bull Si cela eacutechoue nous le signalons agrave lutilisateur agrave laide de la fonction print_warning

bull Le type gchar est une redeacutefinition du type char par la glib (il en va de mecircme pour tous les autres types du C)privileacutegiez ces types lorsque vous utilisez des fonctions de cette bibliothegraveques

Mais quest-ce donc cette fonction print_warning Cest une fonction que nous allons creacuteer semblable agrave printf quisignalera agrave lutilisateur quune erreur non critique est survenue Comme nous navons pas encore abordeacute les boicirctesde dialogue pour afficher un message il sagira pour linstant dune simple redeacutefinition de printf Pendant que noussommes dans laffichage des messages nous allons aussi creacuteer deux fonctions print_info et print_error qui vontrespectivement afficher un message dinformation et un message derreur critique (ce qui entraicircne la terminaison duprogramme) tout ceci dans un nouveau fichier errorc

errorhifndef H_ERRORdefine H_ERROR

void print_info (char )void print_warning (char )void print_error (char )

endif not H_ERROR

errorcinclude ltstdarghgtinclude ltstdiohgtinclude ltstdlibhgtinclude errorh

void print_info (char format ) va_list va

va_start (va format) printf (Information ) vprintf (format va) printf (n)

void print_warning (char format ) va_list va

va_start (va format) fprintf (stderr Erreur ) vfprintf (stderr format va) fprintf (stderr n)

void print_error (char format ) va_list va

va_start (va format) fprintf (stderr Erreur fatale ) vfprintf (stderr format va) fprintf (stderr n) exit (EXIT_FAILURE)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 18 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

Pour en finir avec louverture dun fichier il nous reste agrave copier contents dans le GtkTextView En fait le GtkTextViewne gegravere que la forme pour modifier le contenu il faut passer par les GtkTextBuffer Commenccedilons donc par reacutecupeacutererce fameux GtkTextBuffer

callbackc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (p_text_view)

Et pour finir on utilise la fonction

void gtk_text_buffer_insert (GtkTextBuffer buffer GtkTextIter iter const gchar text gint len)

Reacutecapitulons buffer est le GtkTextBuffer que lon vient de reacutecupeacuterer text cest le texte agrave afficher et len la taille dece dernier (ou -1 sil sagit dune chaicircne de caractegraveres au sens du langage C)

Mais quest-ce donc ce GtkTextIter On peut voir cela comme un curseur virtuel qui indique la position agrave laquelleeffectuer linsertion de texte dans le GtkTextBuffer (5) Allons voir ce que la documentation peut nous apprendreagrave leur sujet (6)

typedef struct GtkTextIter is an opaque datatype ignore all these fields Initialize the iter with gtk_text_buffer_get_iter_ functions GtkTextIter

Voilagrave on a notre solution suffit de rechercher les fonctions commenccedilant par gtk_text_buffer_get_iter_ voici la liste

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)

La fonction gtk_text_buffer_get_iter_at_line fait parfaitement laffaire

callbackc GtkTextIter iter

gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1)

Cependant si vous ne voulez pas avoir de problegravemes avec le codage des caractegraveres il vaut mieux convertir le codagelocal vers utf8 Voici le reacutesultat final

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 19 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gchar utf8 = NULL GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_text_buffer_insert (p_text_buffer ampiter utf8 -1) g_free (utf8) utf8 = NULL

V-D - La petite touche finale

Pour finir cette laborieuse partie sur une petite touche estheacutetique nous allons demander agrave GTK+ de nous lancerlapplication en plein eacutecran Pour se faire il suffit dajouter lors de la creacuteation de la fenecirctre principale

maincgtk_window_maximize (GTK_WINDOW (p_window))

On peut mecircme se permettre une pointe dexcentriciteacute en modifiant le titre de notre fenecirctre

maincgtk_window_set_title (GTK_WINDOW (p_window) Editeur de texte en GTK+)

V-E - Code source

chapitre5zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 20 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VI - Choisir un fichier

VI-A - Aperccedilu

Cliquez pour agrandir

VI-B - Utilisation dun GtkFileChooserFile

Jusquagrave preacutesent lutilisateur navait pas le choix quant au fichier agrave ouvrir heureusement GTK+ vient agrave notre aide gracircceau widget GtkFileChooserFile qui est tout simplement une boicircte de dialogue qui propose agrave lutilisateur de seacutelectionnerun fichier dans son arborescence disque

Commenccedilons par creacuteer notre boicircte de dialogue dans la fonction cb_open

callbackcvoid cb_open (GtkWidget p_widget gpointer user_data) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Ouvrir un fichier NULL GTK_FILE_CHOOSER_ACTION_OPEN GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_OPEN GTK_RESPONSE_ACCEPT NULL)

Cette fonction neacutecessite le titre de la boicircte de dialogue une fenecirctre parente le type daction (ici on souhaite ouvrir unfichier GTK+ autorisera lutilisateur agrave seacutelectionner uniquement les fichiers existants) Pour finir il sagit dun couple devaleurs GTK_STOCK_ITEMGTK_STOCK_RESPONSE qui permet de creacuteer un bouton utilisant le stock ID speacutecifieacuteet lorsque celui-ci est cliqueacute la fonction servant agrave lancer la boicircte de dialogue retournera le reacuteponse ID correspondantIl existe une seacuterie de valeurs deacutefinies par GTK+ quil est conseilleacute dutiliser

typedef enum GTK returns this if a response widget has no response_id or if the dialog gets programmatically hidden or destroyed GTK_RESPONSE_NONE = -1

GTK wont return these unless you pass them in as the response for an action widget They are for your convenience GTK_RESPONSE_REJECT = -2 GTK_RESPONSE_ACCEPT = -3

If the dialog is deleted GTK_RESPONSE_DELETE_EVENT = -4

These are returned from GTK dialogs and you can also use them yourself if you like GTK_RESPONSE_OK = -5 GTK_RESPONSE_CANCEL = -6 GTK_RESPONSE_CLOSE = -7 GTK_RESPONSE_YES = -8

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 21 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GTK_RESPONSE_NO = -9 GTK_RESPONSE_APPLY = -10 GTK_RESPONSE_HELP = -11 GtkResponseType

Nous indiquons la fin des couples stock idreacuteponse id avec la valeur NULL

Une fois la boicircte de dialogue creacuteee on demande agrave GTK+ de lafficher gracircce agrave la fonction gtk_dialog_run puis onreacutecupegravere sa valeur de retour qui correspond au bouton cliqueacute par lutilisateur

callbackc if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

Ici ce qui nous inteacuteresse cest lorsque que lutilisateur clique sur le bouton ouvrir (donc gtk_dialog_run renvoieGTK_RESPONSE_ACCEPT) dans ce cas il nous suffit de reacutecupeacuterer le nom du fichier seacutelectionneacute puis de louvrir

callbackc gchar file_name = NULL

file_name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) open_file (file_name GTK_TEXT_VIEW (user_data)) g_free (file_name) file_name = NULL

Pour finir dans tous les cas on noublie pas de deacutetruire la boicircte de dialogue

callbackc gtk_widget_destroy (p_dialog)

Et voilagrave le travail lutilisateur peut ouvrir le fichier quil souhaite

VI-C - Code source

chapitre6zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 22 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VII - Interlude

Avant daller plus loin dans lameacutelioration de linterface de notre eacutediteur il est neacutecessaire de modifier sonfonctionnement interne (ne vous inquieacutetez je nai pas dit chambouler) en effet souvenez-vous dans lintroduction jaieacutevoqueacute la possibiliteacutes douvrir plusieurs documents gracircce agrave un systegraveme donglets Pour cela il faut sauvegarder lesproprieacuteteacutes de chaque document ouvert Pris agrave temps ce genre de modification nest pas trop lourde mais si nousattendons cela risque de devenir un vrai casse tecircte

Pour cela nous allons utiliser une structure de donneacutee pour chaque document ouvert qui devra garder en meacutemoirele chemin complet du fichier (ou NULL si le document nest pas encore sauvegarder) sil agrave eacutetait modifier depuis laderniegravere sauvegarde et le GtkTextView qui sert agrave son affichage Voici donc la structure qui va nous servir

documenthtypedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

Sachant que nous serons ameneacute agrave stocker plusieurs occurrences de cette structure il serait bon de reacutefleacutechir degravesmaintenant agrave la structure de donneacutee agrave utiliser pour les stocker La premiegravere ideacutee qui vient agrave lesprit est un tableaualloueacute dynamiquement cependant lutilisateur peut souhaiter fermer un document qui se trouve au milieu on estalors obligeacute de deacutecaler toutes les cellules en amont Dans ce cas il parait naturel dutiliser une liste chaicircneacutee Parchance la glib propose une bibliothegraveque de gestion des listes chaicircneacutees cela nous fera gagner du temps le momentvenu Pour linstant on se contente de creacuteer une structure de donneacutees qui contiendra tous les documents ouverts(stockeacutee dans une GList) et un pointeur sur le document actif (actuellement comme nous navons quun documentouvert en mecircme temps on manipulera uniquement ce pointeur)

documenthtypedef struct GList tous document_t actif docs_t

Maintenant se pose le problegraveme de savoir comment transmettre cette structure On pourrait se servir du paramegravetreuser_data preacutesent dans toutes les fonctions callback mais certaines fonctions utilise deacutejagrave ce paramegravetre (la fonctioncb_open par exemple) il faudrait creacuteer un champs suppleacutementaire dans notre structure documents_s Une solutionplus simple est de creacuteer une variable globale agrave lensemble du programme Ceux qui passe reacuteguliegraverement sur le forumC savent que cest fortement deacuteconseilleacute mais ici nous nous trouvons dans lune des rares exceptions agrave la regravegle Detoute faccedilon cela revient au mecircme que de passer ladresse de notre structure agrave toutes les fonctions callback Nousdeacutefinissons donc un nouveau fichier den-tecircte

documenthifndef H_DOCUMENTdefine H_DOCUMENT

include ltgtkgtkhgt

typedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 23 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

documenthtypedef struct GList tous document_t actif docs_t

extern docs_t docs

endif not H_DOCUMENT

Et dans le fichier mainc

maincinclude documenth

docs_t docs = NULL NULL

Pour linstant la seule fonction qui modifie leacutetat dun document est la fonction open_file il faut donc inclure documenthdans callbackc et modifier leacutegegraverement la fonction pour enregistrer le document ouvert

callbackc if (g_file_get_contents (file_name ampcontents NULL NULL)) Pour linstant il faut allouer la memoire par la suite on modifira simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = g_strdup (file_name) Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = p_text_view Le document vient detre ouvert il nest donc pas modifie docsactif-gtsauve = TRUE

Ne soyez pas choqueacute si je ne teste pas le retour de la fonction g_malloc pour veacuterifier quilnest pas NULL En effet cette derniegravere met fin agrave lapplication si lallocation eacutechoue

VII-A - Code source

chapitre7zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 24 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VIII - Sauvegarder les modification

VIII-A - Aperccedilu

Cliquez pour agrandir

VIII-B - Enregistrer

Avant de pouvoir sauvegarder un document il faut quil soit modifieacute Comment savoir que le contenu du fichier a eacuteteacutemodifier Gracircce au signal changed du GtkTextBuffer que nous interceptons gracircce agrave la fonction cb_modifie

mainc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (p_text_view)) g_signal_connect (G_OBJECT (p_text_buffer) changed G_CALLBACK (cb_modifie) NULL)

Cette derniegravere modifie simplement le champ sauve du document

callbackcvoid cb_modifie (GtkWidget p_widget gpointer user_data) if (docsactif) docsactif-gtsauve = FALSE

Pour la sauvegarde il faut distinguer deux cas soit il sagit de la premiegravere sauvegarde du fichier il faut alors demanderle nom du fichier agrave lutilisateur (cela ressemble fortement agrave louverture dun fichier) soit le fichier est deacutejagrave preacutesent surle disque il suffit de remplacer son contenu par celui du GtkTextViewer Nous avons convenu quun fichier qui neacutetaitpas encore enregistreacute avait sa proprieacuteteacute chemin agrave NULL

Bien sucircr cela na lieu que si un fichier est ouvert et quil a eacuteteacute modifieacute depuis sa derniegravere sauvegarde

callbackcvoid cb_save (GtkWidget p_widget gpointer user_data) if (docsactif) if (docsactif-gtsauve) Le fichier na pas encore ete enregistre if (docsactif-gtchemin) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Sauvegarder le fichier NULL GTK_FILE_CHOOSER_ACTION_SAVE GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_SAVE GTK_RESPONSE_ACCEPT NULL) if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 25 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc docsactif-gtchemin = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) gtk_widget_destroy (p_dialog) Soit le fichier a deja ete enregistre soit lutilisateur vient de nous fournir son nouvel enplacement on peut donc lenregistrer if (docsactif-gtchemin) else print_warning (Aucun document ouvert)

Il nous reste plus quagrave reacutecupeacuterer le contenu du GtkTextViewer et le copier dans le fichier chemin sans oublier dereconvertir le texte dans le codage local

callbackc FILE fichier = NULL

fichier = fopen (docsactif-gtchemin w) if (fichier) gchar contents = NULL gchar locale = NULL GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) contents = gtk_text_buffer_get_text (p_text_buffer ampstart ampend FALSE) locale = g_locale_from_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL fprintf (fichier s locale) g_free (locale) locale = NULL fclose (fichier) fichier = NULL docsactif-gtsauve = TRUE else print_warning (Impossible de sauvegarder le fichier s docsactif-gtchemin)

Le dernier paramegravetre de la fonction gtk_text_buffer_get_text est mis agrave FALSE car nous ne voulons pas enregistrerles caractegraveres invisibles preacutesent dans le GtkTextBuffer Ces caractegraveres servent agrave mettre en forme le texte (taillecouleur) nous pourrions creacuteer un nouveau format de fichier pour enregistrer la mise en forme

VIII-C - Enregistrer sous

Pour enregistrer notre document sous un autre nom il suffit de faire croire agrave cb_save que le document na pas encoreeacutetait enregistreacute tout simplement en changeant chemin agrave NULL et sauve agrave FALSE

callbackcvoid cb_saveas (GtkWidget p_widget gpointer user_data)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 26 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (docsactif) document_t tmp = docsactif

docsactif-gtchemin = NULL docsactif-gtsauve = FALSE cb_save (p_widget user_data) if (docsactif-gtsauve) (docsactif) = tmp else print_warning (Aucun document ouvert)

Il ne faut pas oublier que lutilisateur peut annuler lenregistrement de ce fait nous sauvegardons leacutetat du documentet si la sauvegarde na pas eu lieu on le restaure

VIII-D - Code source

chapitre8zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 27 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IX - Creacuteer un nouveau document

IX-A - Aperccedilu

Cliquez pour agrandir

IX-B - Nouveau fichier

Maintenant que lutilisateur peut ouvrir et fermer un fichier il est inteacuteressant de lui donner la possibiliteacute den creacuteerun nouveau Je ne reviens pas sur la creacuteation du bouton (ccedila devrait deacutejagrave ecirctre fait D) passons directement agrave lafonction cb_new

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) Pour linstant il faut allouer la memoire par la suite on modifiera simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = NULL Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = GTK_TEXT_VIEW (user_data) Le document vient detre creer il nest donc pas modifie docsactif-gtsauve = TRUE gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Je ne sais pas vous mais pour ma part jai fait un copiercoller de la fonction open_file Et oui ouvrir un document peutse reacutesumer agrave creacuteer un document vide puis remplir le GtkTextView avec le fichier souhaiteacute On peut donc simplifiernotre fonction open_file ainsi

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

cb_new (NULL p_text_view) gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE) p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1) Nous sommes obliges de remetre sauve a TRUE car linsertion du contenu du fichier dans le GtkTextView a appele cb_modfie docsactif-gtsauve = TRUE else print_warning (Impossible douvrir le fichier sn file_name)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 28 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc

Cest beau la factorisation du code Par contre nous sommes obligeacutes de remettre sauve agrave TRUE car nous avonsmodifieacute le GtkTextBuffer

IX-C - Code source

chapitre9zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 29 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

X - Fermer

X-A - Aperccedilu

Cliquez pour agrandir

X-B - Fermer un fichier

Maintenant que nous allouons de la meacutemoire il faut la libeacuterer agrave un endroit Logiquement cela va ecirctre fait agrave la fermeturedu document en guise dexercice je vous laisse creacuteer le bouton dans notre boicircte agrave bouton

Allez je vous aide le stock id correspondant est GTK_STOCK_CLOSE

Voilagrave maintenant si tout cest bien passeacute vous devriez ecirctre arriveacute dans le fichier callbackc avec quelque choseressemblant agrave

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data)

Lorsque lon ferme un document il faut vider le GtkTextView (avec les onglets on se contentera de le supprimer)pour cela il faut reacutecupeacuterer le deacutebut et la fin du GtkTextBuffer et demander agrave GTK+ de supprimer tout ce qui ce trouveentre les deux iteacuterateurs

callbackc Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) gtk_text_buffer_delete (p_text_buffer ampstart ampend) else print_warning (Aucun document ouvert)

Bien sucircr il ne faut pas oublier de libeacuterer la meacutemoire

callbackc g_free (docsactif-gtchemin) docsactif-gtchemin = NULL docsactif-gtp_text_view = NULL g_free (docsactif) docsactif = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 30 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour symboliser la fermeture dun document nous deacutesactivons le GtkTextView lors de la fermeture (ne pas oublierde le faire aussi dans mainc)

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) FALSE)

Et nous le reacuteactivons lors de louverture si celle si reacuteussie

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Lorsque lutilisateur quitte lapplication il faut bien sucircr fermer le document sil y en a un ouvert

void cb_quit (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data) gtk_main_quit()

Et aussi lorsquil creacuteeacute un nouveau document (et par conseacutequent lorsquil ouvre un fichier puisque lon fait appel agravecb_new)

void cb_new (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data)

X-C - Enregistrer avant de fermer

Si le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde geacuteneacuteralement le programme le signale agrave lutilisateur etlui propose de sauvegarder ou dannuler la fermeture Pour se faire nous devons modifier la fonction cb_close avantde fermer le document nous allons afficher une boicircte de dialogue

Pour creacuteer une boicircte de dialogue simplement il existe la classe GtkDialog et comme nous avons besoin de boutons(pour que lutilisateur fasse son choix) nous allons creacuteer notre boicircte avec la fonction

GtkWidget gtk_dialog_new_with_buttons (const gchar title GtkWindow parent GtkDialogFlags flags const gchar first_button_text )

Nous retrouvons les mecircmes options que pour le GtkFileChooserDialog mis agrave part option du type GtkDialogFlags

typedef enum GTK_DIALOG_MODAL = 1 ltlt 0 appel gtk_window_set_modal (win TRUE) GTK_DIALOG_DESTROY_WITH_PARENT = 1 ltlt 1 appel gtk_window_set_destroy_with_parent () GTK_DIALOG_NO_SEPARATOR = 1 ltlt 2 Pas de barre de separation au dessus des boutons GtkDialogFlags

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 31 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Nous nous contenterons de rendre notre fenecirctre modale (7)

Pour avoir accegraves agrave notre fenecirctre principale nous ajoutons un champs p_main_window agrave notre structure globaledocs_t que nous initialisons dans la fonction main

mainc docsp_main_window = GTK_WINDOW (p_window)

Il nous reste plus qua creacuteer notre boicircte de dialogue avec trois boutons Oui Non Annuler

callbackc if (docsactif-gtsauve) GtkWidget p_dialog = NULL

p_dialog = gtk_dialog_new_with_buttons (Sauvegarder docsp_main_window GTK_DIALOG_MODAL GTK_STOCK_YES GTK_RESPONSE_YES GTK_STOCK_NO GTK_RESPONSE_NO GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL NULL)

Nous obtenons donc une structure de type GtkDialog

typedef struct GtkWidget vbox GtkWidget action_area GtkDialog

Nous remarquons que cette structure contient deux membres qui permettent dacceacuteder agrave une GtkBox ougrave nous allonsajouter le contenu de la fenecirctre et agrave la partie contenant les boutons

Ensuite la construction de la fenecirctre est identique agrave celle de la fenecirctre principale ici nous nous contenterons dajouterun GtkLabel

callbackc GtkWidget p_label = NULL p_label = gtk_label_new (Voulez-vous sauvegarder les modifications ) gtk_box_pack_start (GTK_BOX (GTK_DIALOG (p_dialog)-gtvbox) p_label TRUE TRUE 0)

Une fois notre fenecirctre precircte il suffit de faire appel agrave la fonction gtk_dialog_run qui va afficher notre GtkDialog et nousretourner le reacuteponse id correspondant au bouton cliqueacute par lutilisateur

callbackc switch (gtk_dialog_run (GTK_DIALOG (p_dialog))) case GTK_RESPONSE_YES cb_save (p_widget user_data) break case GTK_RESPONSE_NO break case GTK_RESPONSE_CANCEL gtk_widget_destroy (p_dialog) return break

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 32 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc gtk_widget_destroy (p_dialog)

Si lutilisateur clique sur non on ne fait rien (le document sera simplement fermeacute) sur oui on enregistre avant defermer et pour finir sil annule on quitte la fonction

X-D - Code source

chapitre10zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 33 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XI - Les barres de deacutefilement

XI-A - Aperccedilu

Cliquez pour agrandir

XI-B - Ajouter des barres de deacutefilement

Apregraves le dernier chapitre quelque peu laborieux voici une partie plus simple mais qui va rendre notre applicationplus pratique En effet si vous avez essayeacute douvrir un fichier de grande taille vous avez pu remarquer que pourpouvoir lire la fin du fichier il fallait utiliser les touches du clavier pas tregraves convivial

Pour rendre la navigation plus aiseacutee on utilise des barres de deacutefilement

mainc GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_scrolled_window TRUE TRUE 0)

Creation de la zone de texte gtk_container_add (GTK_CONTAINER (p_scrolled_window) p_text_view)

Le constructeur de notre GtkScrolledWindow prend en argument deux GtkAdjustment qui permettent de deacutefinirdiffeacuterentes proprieacuteteacutes de la barre de deacutefilement (taille dune page la position de deacutepart) nous laissons GTK+ faireen passant NULL

Cest un bon deacutebut mais estheacutetiquement on peut faire mieux mecircme sil nest pas utile davoir une barre de deacutefilementelle est quand mecircme afficheacutee On peut demander agrave GTK+ de les afficher que si cela est neacutecessaire

mainc gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC)

En fait nous avons de la chance car la classe GtkTextView fait partie des widget qui supporte de faccedilon native les barresde deacutefilement Comment le savoir Ce genre de widget possegravede une ou deux proprieacuteteacutes de type GtkAdjustment (unepour la barre verticale lautre pour la barre horizontale) Actuellement seulement trois classes en sont capables lesGtkTextView les GtkTreeView et les GtkLayout

Comment faire pour les autres widgets Il faut passer par une classe adaptateur GtkViewport afin de creacuteer lesGtkAdjustment

XI-C - Code source

chapitre11zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 34 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XII - Les menus

XII-A - Aperccedilu

Cliquez pour agrandir

XII-B - Creacuteation du menu

Pour simplifier nous avons utiliseacute des boutons pour permettre agrave lutilisateur de creacuteer un document ouvrir un fichierMais il est plus courant dutiliser un menu pour afficher ces options GTK+ propose trois maniegraveres de creacuteer un menu

bull GtkItemFactory cette meacutethode est obsolegravete depuis la version 24 de GTK+

bull GtkUIManager cest ce quon appel une usine agrave gaz pour en savoir plus vous pouvez vous reporter aututoriel Utilisation de GtkUIManager

bull GtkMenu cest ce widget que nous allons eacutetudier il permet de creacuteer un menu manuellement (agrave lopposeacute deGtkUIManager)

Un menu selon GTK+ est composeacute de plusieurs eacuteleacutements

bull GtkMenuBar la barre de menu elle-mecircme

bull GtkMenu la partie deacuteroulante qui contient les diffeacuterents eacuteleacutements

bull GtkMenuItem cest sur ce widget que lutilisateur clique pour lancer une action

Pour commencer faisons linventaire de ce que nous avons besoin

bull Un GtkMenuBar qui sert de base au menu

bull Un GtkMenu pour commencer nous nous aurons dun menu Fichier

bull Six GtkMenuItem pour remplacer nos six boutons

Commenccedilons par la creacuteation du menu nous mettons ce code dans un nouveau fichier dont seul la fonction menu_newsera accessible

menucGtkMenuBar menu_new (gpointer user_data) GtkWidget p_menu_bar = NULL

p_menu_bar = gtk_menu_bar_new () return GTK_MENU_BAR (p_menu_bar)

Le paramegravetre user_data nous servira lors de la connexion des callbacks (nous en avons besoin pour les fonctionscb_new et cb_open)

Ensuite nous allons creacuteer notre sous menu Fichier

menuc Menu Fichier

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 35 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

menuc GtkWidget p_menu = NULL GtkWidget p_menu_item = NULL

p_menu = gtk_menu_new () p_menu_item = gtk_menu_item_new_with_mnemonic (_Fichier) gtk_menu_item_set_submenu (GTK_MENU_ITEM (p_menu_item) p_menu) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu_bar) p_menu_item) return GTK_MENU_BAR (p_menu_bar)

Un sous menu est en fait un GtkMenuItem auquel on assigne un GtkMenu Il faut bien sucircr terminer la creacuteation dusous-menu en lajoutant agrave la barre de menu

Pour finir nous creacuteons les eacuteleacutements du menu les GtkItemMenu Il existe plusieurs types deacuteleacutements (comparableaux diffeacuterents types de bouton) pour commencer nous nutiliserons que le type de base Comme cette opeacuteration estreacutepeacutetitive nous allons creacuteer une fonction pour le faire

menucstatic void menu_item_new (GtkMenu p_menu const gchar title GCallback callback gpointer user_data) GtkWidget p_menu_item = NULL

p_menu_item = gtk_menu_item_new_with_mnemonic (title) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu) p_menu_item) g_signal_connect (G_OBJECT (p_menu_item) activate callback user_data)

Pour permettre agrave lutilisateur dacceacuteder aux diffeacuterents eacuteleacutements du menu agrave laide de la touche ltAltgt nous utilisonsdes mneacutemoniques par exemple pour quitter leacutediteur il suffit de faite Alt+F puis Q Et voici le code pour creacuteer nossix eacuteleacutements du menu

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau G_CALLBACK (cb_new) user_data) menu_item_new (GTK_MENU (p_menu) _Ouvrir G_CALLBACK (cb_open) user_data) menu_item_new (GTK_MENU (p_menu) _Enregistrer G_CALLBACK (cb_save) user_data) menu_item_new (GTK_MENU (p_menu) Enregistrer _sous G_CALLBACK (cb_saveas) user_data) menu_item_new (GTK_MENU (p_menu) _Fermer G_CALLBACK (cb_close) user_data) menu_item_new (GTK_MENU (p_menu) _Quitter G_CALLBACK (cb_quit) user_data)

Voilagrave notre menu est creacuteeacute il nous reste plus quagrave linteacutegrer agrave notre fenecirctre

mainc gtk_box_pack_start (GTK_BOX (p_main_box) GTK_WIDGET (menu_new (p_text_view)) FALSE FALSE 0)

Le problegraveme cest que nous avons besoin de passer le GtkTextView lors de la creacuteation du menu (qui est utiliseacute par lesfonctions cb_new et cb_open) or celui-ci est creacuteeacute apregraves le menu (puisque nous creacuteons les widgets dans lordre ougrave ilfaut les inteacutegrer agrave linterface (8) ) nous devons creacuteer le GtkTextView (seul lappel agrave gtk_text_view_new est deacuteplaceacute)

XII-C - Code source

chapitre12zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 36 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIII - Les barres doutils

XIII-A - Aperccedilu

Cliquez pour agrandir

XIII-B - Creacuteation dune barre doutils

La creacuteation dune barre doutils ressemble fort agrave celle dun menu en plus simple puisquil ny a pas de sous menu on creacutee notre barre doutils (gtk_toolbar_new) puis les eacuteleacutements de la barre pour cela on utilise des boutons(gtk_tool_button_new_from_stock) que lon inseacutere dans la barre (gtk_toolbar_insert) Pas conseacutequent notre fichierbarreoutilsc ressemble agrave menuc

barreoutilscinclude ltgtkgtkhgtinclude callbackhinclude barreoutilsh

static void toolbar_item_new (GtkToolbar const gchar GCallback gpointer)

GtkToolbar toolbar_new (gpointer user_data) GtkWidget p_toolbar = NULL

p_toolbar = gtk_toolbar_new () toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_NEW G_CALLBACK (cb_new) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_OPEN G_CALLBACK (cb_open) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE G_CALLBACK (cb_save) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE_AS G_CALLBACK (cb_saveas) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_CLOSE G_CALLBACK (cb_close) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_QUIT G_CALLBACK (cb_quit) user_data) return GTK_TOOLBAR (p_toolbar)

static void toolbar_item_new (GtkToolbar p_toolbar const gchar stock_id GCallback callback gpointer user_data) GtkToolItem p_tool_item = NULL

p_tool_item = gtk_tool_button_new_from_stock (stock_id) g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data) gtk_toolbar_insert (p_toolbar p_tool_item -1)

Le code nest pas complet car lorsque jexeacutecute le programme GTK+ affiche en plus des icocircnes le texte sous lesboutons Pour modifier cela il suffit dajouter une ligne de code

barreoutilsc gtk_toolbar_set_style (GTK_TOOLBAR (p_toolbar) GTK_TOOLBAR_ICONS)

Pourquoi gtk_tool_button_new_from_stock retourne un GtkToolItem et non un GtkWidgetcomme nous avons eacuteteacute habitueacute jusquagrave preacutesent Il sagit dune bizarrerie de GTK+ dontje ne connais pas la raison

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 37 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour anticiper un changement dinterface (dans GTK+ 30 peut ecirctre ) nous aurions pueacutecrire

Gtkwidget p_tool_item = NULL

p_tool_item = GTK_WIDGET (gtk_tool_button_new_from_stock (stock_id))g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data)gtk_toolbar_insert (p_toolbar GTK_TOOL_ITEM (p_tool_item) -1)

XIII-C - Code source

chapitre13zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 38 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIV - Les racourcis clavier

XIV-A - Aperccedilu

Cliquez pour agrandir

XIV-B - Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mneacutemoniques ces derniers permettent dacceacuteder agrave un eacuteleacutementseacutequentiellement alors que les raccourcis appellent une fonction si lutilisateur appuie simultaneacutement sur une ouplusieurs touches (geacuteneacuteralement de la forme ltModificateurgtTouche ougrave Modificateur repreacutesente les touches ShiftAlt et Control) Ce raccourci peut ecirctre attacheacute agrave un eacuteleacutement du menu mais ceci nest pas obligatoire

Les raccourcis sont regroupeacutes en groupe dans un GtkAccelGroup quil faut commencer par creacuteer

raccourciscinclude ltgtkgtkhgtinclude callbackhinclude raccourcish

GtkAccelGroup accel_group_new (gpointer user_data) GtkAccelGroup p_accel_group = NULL

p_accel_group = gtk_accel_group_new () return p_accel_group

Vous commencez agrave avoir lhabitude de cette organisation nous allons donc creacuteer une fonction qui va se chargerdajouter un raccourci au groupe

raccourciscstatic void accelerator_new (GtkAccelGroup p_accel_group const gchar accelerator const gchar accel_path GCallback callback gpointer user_data) guint key GdkModifierType mods GClosure closure = NULL

gtk_accelerator_parse (accelerator ampkey ampmods) closure = g_cclosure_new (callback user_data NULL) gtk_accel_group_connect (p_accel_group key mods GTK_ACCEL_VISIBLE closure) gtk_accel_map_add_entry (accel_path key mods)

La fonction gtk_accelerator_parse permet de deacutecomposer une chaicircne de caractegraveres de la forme ltControlgtF1 ouencore ltAltgtA en numeacutero de touche et modificateur

En plus des touches pour creacuteer un raccourci clavier nous avons besoin dune fonction agrave appeler lorsque lutilisateurappuie sur les touches speacutecifieacutees gtk_accel_group_connect attend une fonction du type GClosure regardons ladocumentation de gobject pour savoir agrave quoi cela correspond

typedef struct

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 3 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

X-D - Code sourceXI - Les barres de deacutefilement

XI-A - AperccediluXI-B - Ajouter des barres de deacutefilementXI-C - Code source

XII - Les menusXII-A - AperccediluXII-B - Creacuteation du menuXII-C - Code source

XIII - Les barres doutilsXIII-A - AperccediluXIII-B - Creacuteation dune barre doutilsXIII-C - Code source

XIV - Les racourcis clavierXIV-A - AperccediluXIV-B - Mise en place des raccourcis clavierXIV-C - Code source

XV - Messages derreurXV-A - AperccediluXV-B - Ameacutelioration de nos fonctions daffichage derreurXV-C - Code source

XVI - Ouvrir plusieurs fichiers en mecircme tempsXVI-A - AperccediluXVI-B - Mise en place des ongletsXVI-C - Changement de pageXVI-D - Fermer un ongletXVI-E - Fermer tous les ongletsXVI-F - Modifier le titre de la pageXVI-G - Code source

XVII - Afficher larborescence du disqueXVII-A - AperccediluXVII-B - Preacuteparons le terrainXVII-C - Creacuteation dun GtkTreeView

XVII-C-1 - Creacuteation du magasinXVII-C-2 - Affichage de larborescenceXVII-C-3 - Seacutelectionner un fichier

XVII-D - Code sourceXVIII - Notre signature

XVIII-A - AperccediluXVIII-B - Boicircte A proposXVIII-C - Code source

XIX - ConclusionXIX-A - Cest deacutejagrave fini XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 4 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

I - Introduction

I-A - But de ce tutoriel

Pour vous initier aux joies de la programmation dinterfaces graphiques plutocirct que de faire un catalogue de toutesles fonctions de la bibliothegraveque ce qui serait long et vite ennuyeux je vous propose de construire pas agrave pas uneapplication un eacutediteur de texte Pas un simple eacutediteur de texte histoire de faire le tour des possibiliteacutes de GTK+nous allons y ajouter pas agrave pas les fonctionnaliteacutes suivantes

bull Creacuteation ouverture enregistrement de fichiers textes

bull Possibiliteacute douvrir plusieurs fichiers gracircce agrave une navigation par onglets

bull Ouverture rapide dun fichier gracircce agrave une liste de fichiers

Rien dimpressionnant par rapport agrave un traitement de texte mais plus eacutevolueacute et plus pratique quun simple eacutediteurde texte Ce tutoriel est organiseacute de faccedilon agrave ajouter une nouvelle fonctionnaliteacute agrave chaque eacutetape tout en apprenantagrave maicirctriser un ou plusieurs eacuteleacutements de GTK+

Comme je viens de le dire il nest pas question de faire un catalogue de la bibliothegravequecependant avant dutiliser un nouveaux type de widget jen ferai une bregraveve descriptionqui pourra vous servir de pense becircte lors de vos futurs deacuteveloppements Cette descriptioncomportera un aperccedilu pour les widgets graphiques sa hieacuterarchie dheacuteritage ses fonctionsde creacuteations (constructeurs) les fonctions les plus utiliseacutees et les signaux importants dela classe

I-B - Connaissances requises

Le but de ce tutorial est dapprendre agrave maicirctriser GTK+ en partant de zeacutero ou presque en effet avant de vouloir creacuteerune interface graphique il vaut mieux bien connaicirctre le langage C en mode console Pour cela je vous renvoie aucours de la rubrique C

I-C - Quelques mots sur GTK+

I-C-1 - Historique

GTK+ ou the GIMP Toolkit eacutetait agrave lorigine une boicircte agrave outils pour les deacuteveloppeurs du logiciel the GIMP (the GNUImage Manipulation Program) qui comme son nom lindique est un logiciel de manipulation dimages rattacheacute auprojet GNU Au vu de limportance de cette boicircte agrave outils GTK+ a eacuteteacute deacutetacheacute de the GIMP en septembre 1997Depuis il existe deux versions GTK+ 10 et GTK+ 20 versions qui ne sont pas totalement compatibles cependantla premiegravere est encore utiliseacutee dans certaines applications tel que dans le domaine de lembarqueacute du fait de sacomplexiteacute moindre Il est bien eacutevident que cest la seconde version qui est la plus utiliseacutee elle est agrave lorigine denombreux projets tel que le gestionnaire de fenecirctre GNOME (GNU Network Object Model Environment) La derniegravereversion en date est la 281 annonceacutee le 24 Aoucirct 2005

I-C-2 - Structure

Comme preacuteciseacute preacuteceacutedemment GTK+ est une boicircte agrave outils et en tant que tel elle est constitueacutee de plusieursbibliothegraveques indeacutependantes deacuteveloppeacutees par leacutequipe de GTK+

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 5 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

bull La GLib propose un ensemble de fonctions qui couvrent des domaines aussi vastes que les structures dedonneacutees la gestion des threads et des processus de faccedilon portable ou encore un analyseur syntaxique pourles fichiers XML et bien dautre

bull Pango il sagit de la bibliothegraveque daffichage et de rendue de textes

bull ATK

La bibliothegraveque GTK+ en elle-mecircme utilise une approche orienteacutee objet et repose sur plusieurs couches

bull GObject il sagit de la base de limpleacutementation des objets pour la POO

bull GDK bibliothegraveque graphique de bas niveau

bull GTK+ la bibliothegraveque GTK+ elle-mecircme baseacutee sur lutilisation de widgets (1)

Cest bien sucircr cette derniegravere qui nous inteacuteresse ici mais la glib nous sera aussi dune grande aide

I-C-3 - Pourquoi utiliser GTK+

Effectivement pourquoi choisir dutiliser GTK+ plutocirct quune autre bibliothegraveque pour reacutealiser une interface graphiqueVoici quelques arguments

bull GTK+ est sous licence libre LGPL vous pouvez donc lutiliser pour deacutevelopper des programmes libres oucommerciaux

bull La portabiliteacute GTK+ est disponible sur un grand nombre de systegravemes dont Windows Linux Unix et MacOSX

bull GTK+ est deacuteveloppeacutee en C et pour le langage C cependant elle est disponible pour dautres langages telsque Ada C++ (gracircce agrave gtkmm) Java Perl PHP Python Ruby ou plus reacutecemment C

I-D - Installation

I-D-1 - Windows

Pour pouvoir exeacutecuter une application utilisant GTK+ il faut commencer par installer les binaires Pour faciliter leurinstallation il existe un installeur

Si vous utilisez the Gimp utilisez les runtimes proposeacutees sur le sitehttpwwwgimp-winorg

Pour deacutevelopper une application il faut les bibliothegraveques ainsi que les fichiers den-tecircte disponibles sur gtkorg Pourceux qui utilisent CodeBlocks voici la meacutethode agrave suivre Installation de

I-D-2 - Linux

Sous Linux vous disposez sucircrement dun systegraveme de paquets Il vous faudra installer deux paquets le premiercontenant les fichiers permettant dexeacutecuter des programmes utilisant GTK+ le second paquet contient les fichiersneacutecessaires au deacuteveloppement

Une fois linstallation reacuteussie compilez agrave laide de la commande

gcc -Werror -Wall -W -O2 -ansi -pedantic `pkg-config --cflags --libs gtk+-20` c

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 6 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Tous les codes de ce tutoriel ont eacuteteacute testeacutes sous Linux Debian et Windows XP avecCodeBlocks

I-E - La philosophie GTK+

Voici quelques choix qui ont eacuteteacute faits par leacutequipe de deacuteveloppement de GTK+

bull Les noms de fonctions sont de la forme gtk_type_du_widget_action ceci rend les noms des fonctions tregravesexplicites en contre partie ils peuvent ecirctre tregraves longs

bull Tous les objets manipuleacutes sont des GtkWidget pour que GTK+ veacuterifie quil sagit du bon type dobjet lors delappel agrave une fonction chaque type de widget possegravede une macro de la forme GTK_TYPE_DU_WIDGET agraveutiliser pour transtyper vos widgets

bull La gestion des eacuteveacutenements qui modifient le comportement de lapplication (clique de souris pression dunetouche du clavier) se fait gracircce agrave lutilisation de fonctions de rappel (callback) Pour cela on connecte leswidgets agrave des fonctions qui seront appeleacutees lorsque leacuteveacutenement survient

I-F - Quelques notions de POO

La POO ou Programmation Orienteacutee Objet est un mode de programmation baseacutee sur des objets GTK+ utilisant ceprincipe (2) je vais vous en expliquer les principes de bases

Plutocirct que le deacuteroulement du programme soit reacutegie par une suite dinstruction en POO il est reacutegi par la creacuteationlinteraction et la destruction dobjets en reacutesumeacute la vie des objets qui le composent Un objets est une entiteacute (leparallegravele avec la vie courante est simple un objet pourrait ecirctre un ordinateur) en C on pourrait se repreacutesenter unobjet comme une structure de donneacutees

Un objet est composeacute de proprieacuteteacutes (ce qui correspond agrave nos variables) et de meacutethodes (des fonctions) Pour creacuteerun objet on fait appel agrave son constructeur il sagit dune fonction qui a pour but de creacuteer et dinitialiser lobjet A la finde sa vie lobjet doit ecirctre deacutetruit cest le but du destructeur

Dans la vie courante on peut creacuteer des objets complexes agrave partir de briques de base il est possible de creacuteer denouveaux objets en se basant sur un ou plusieurs objets ce meacutecanisme est appeler heacuteritage (on parle dheacuteritagemultiple lorsquil met en jeu plusieurs objets parents) Lobjet ainsi obtenu heacuterite des proprieacuteteacutes et des meacutethodes deses parents tout en pouvant modifier leur comportement et creacuteer ses propres proprieacuteteacutes et meacutethodes

Lorsque lon souhaite creacuteer un patron pour de futures classes plutocirct que de creacuteer une classe de base qui ne serajamais instancieacutee il est possible de creacuteer une interface

Le dernier concept de POO qui va nous servir dans ce tutoriel est le polymorphisme Ceci permet agrave un objet (prenonspar exemple camion) de se comporter comme lun de ses parents (dans le cas du camion il peut ecirctre vu comme unveacutehicule au mecircme titre quune voiture) Ceci est aussi valable pour des classes impleacutementant la mecircme interface

Pour vous initier aux joies de la programmation orienteacutee objet en C je vous conseille le tutoriel de CGI POO en C

I-G - Notre premier programme

Un programme qui utilise GTK+ est un programme eacutecrit en C avant tout il contient donc le code de base de toutprogramme C

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 7 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

maincinclude ltstdlibhgt

int main (int argc char argv) return EXIT_SUCCESS

Pour pouvoir utiliser les fonctions de GTK+ il faut bien sucircr inclure le fichier den-tecircte correspondant

include ltgtkgtkhgt

La premiegravere chose agrave faire est dinitialiser la machinerie GTK+ gracircce agrave la fonction gtk_init

void gtk_init (int argc char argv)

Cette fonction reccediloit les arguments passeacutes en ligne de commande ceux qui sont speacutecifiques agrave GTK+ sont ensuiteretireacutes de la liste dougrave lutilisation des pointeurs

Ensuite il nous faut creacuteer tous les widgets dont nous avons besoin si neacutecessaire modifier leurs paramegravetres pardeacutefaut les connecter agrave des fonctions callback et ensuite demander leur affichage (tout ceci sera expliciteacute dans lasuite du tutoriel) Une fois la fenecirctre principale creacuteeacutee il suffit de lancer la boucle principale de GTK+

void gtk_main (void)

Cette fonction est une boucle sans fin (seule la fonction gtk_main_quit permet den sortir) qui se charge de geacuterer ledeacuteroulement de notre programme (affichage des widgets envoi de signaux)

Voici donc notre premier programme en CGTK+ qui ne fait rien

maincinclude ltstdlibhgtinclude ltgtkgtkhgt

int main (int argc char argv) Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application

Lancement de la boucle principale gtk_main() return EXIT_SUCCESS

En plus de ne rien faire notre programme ne peut ecirctre termineacute que de faccedilon brutale (Ctrl+C) puisque nous nappelonspas la fonction gtk_main_quit

I-H - Code source

chapitre1zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 8 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

II - Notre premiegravere fenecirctre

II-A - Aperccedilu

II-B - Creacuteation

La fenecirctre principale est repreacutesenteacutee par la classe GtkWindow

La creacuteation dune fenecirctre se fait simplement en appelant le constructeur de cette classe la fonction gtk_window_new

GtkWidget gtk_window_new (GtkWindowType type)

Le seul paramegravetre de cette fonction est le type de fenecirctre souhaiteacute Il ny a que deux possibiliteacutes

bull GTK_WINDOW_TOPLEVEL une fenecirctre classique (cest la base de notre application)

bull GTK_WINDOW_POPUP il sagit dune fenecirctre avec seulement lespace de travail (pas de bordure ni demenu systegraveme)

Cette fonction renvoie un pointeur sur une structure de type GtkWindow (transformer en GtkWidget gracircce aupolymorphisme) qui est lentiteacute qui va nous servir agrave manipuler notre fenecirctre

II-C - Affichage

Si vous essayez deacutecrire un code maintenant vous ne verrez rien pourquoi Tout simplement parce quil faut preacuteciseragrave GTK+ quil faut rendre notre fenecirctre visible gracircce agrave la fonction gtk_widget_show

void gtk_widget_show (GtkWidget widget)

Voici le code qui permet dafficher notre premiegravere fenecirctre

maincinclude ltstdlibhgtinclude ltgtkgtkhgt

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL)

Affichage de la fenetre principale gtk_widget_show (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 9 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Ceux qui se sont essayeacutes agrave la creacuteation dapplications graphiques avec lAPI Windows comprendront la simpliciteacutede ce code

II-D - Destruction

Dans lexemple preacuteceacutedent si vous avez essayeacute de terminer lapplication en fermant la fenecirctre (Alt+F4 ou en cliquantsur la petite croix) vous vous ecirctes peut-ecirctre aperccedilu que lapplication tournait encore en fond cest le mecircme problegravemeque pour le chapitre preacuteceacutedent on ne fait pas appel agrave gtk_main_quit Mais comment appeler cette fonction puisquequune fois gtk_main appeleacutee nous ne pouvons rien faire Cest lagrave quintervient le meacutecanisme des callback A chaqueeacuteveacutenement qui se produit la bibliothegraveque GObject produit un signal si nous souhaitons modifier le comportementpar deacutefaut du signal il suffit de connecter notre fonction callback agrave leacuteveacutenement souhaiteacute

define g_signal_connect(instance detailed_signal c_handler data)

Cette macro permet dintercepter leacuteveacutenement detailed_signal de lobjet instance gracircce agrave la fonction c_handler quidoit ecirctre du type GCallback

void (GCallback) (void)

Les fonctions callback peuvent bien sucircr recevoir des paramegravetres mais leur nature et leur nombre deacutependent ducontexte tout est geacutereacute par la bibliothegraveque GObject Le prototype le plus courant pour une fonction de rappel estle suivant

void callback (GtkWidget p_widget gpointer user_data)

Dont le premier paramegravetre est le widget qui a reccedilu le signal et le second correspond au paramegravetre data de la fonctiong_signal_connect qui nous permet de passer des informations aux fonctions callback Pour finir proprement notreapplication il suffit dintercepter le signal destroy de notre fenecirctre et dy assigner la fonction gtk_main_quit qui neprend pas dargument Voici donc notre premiegravere application fonctionnelle

maincinclude ltstdlibhgtinclude ltgtkgtkhgt

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (gtk_main_quit) NULL)

Affichage de la fenetre principale gtk_widget_show (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

Il est plus courant de creacuteer notre propre fonction de rappel pour quitter le programme ceci permet de libeacuterer lameacutemoire alloueacutee fermer les fichiers ouverts

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 10 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

maincinclude ltstdlibhgtinclude ltgtkgtkhgt

void cb_quit (GtkWidget gpointer)

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (cb_quit) NULL)

Affichage de la fenetre principale gtk_widget_show (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

void cb_quit (GtkWidget p_widget gpointer user_data) gtk_main_quit()

Parametres inutilises (void)p_widget (void)user_data

Le preacutefixe cb_ permet de diffeacuterencier les fonctions callback quil est preacutefeacuterable de regrouper dans un ou plusieursfichiers seacutepareacutes

A la fin de la fonction je transtype les paramegravetres inutiliseacutes pour eacuteviter que moncompilateur mindique des variables non utiliseacutees cest le problegraveme avec les fonctionscallback lAPI nous impose un prototype

II-E - Code source

chapitre2zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 11 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

III - Fermer notre fenecirctre gracircce aux boutons

III-A - Aperccedilu

III-B - Les boutons poussoir

Maintenant que notre programme se termine proprement il est plus convivial de proposer agrave lutilisateur un boutonpour quitter Pour creacuteer un bouton poussoir il existe plusieurs possibiliteacutes

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 premiegravere fonction creacutee un bouton qui peut servir pour contenir nimporte quel autre widget (label image) Si voussouhaitez creacuteer un bouton avec du texte dessus utilisez directement la seconde fonction qui prend en argument letexte agrave afficher Si vous souhaitez ajouter un raccourci clavier (accessible avec la touche Alt) la troisiegraveme fonctionpermet den speacutecifier un en faisant preacuteceacuteder une lettre (geacuteneacuteralement la premiegravere) dun underscore _ (si voussouhaitez afficher le caractegravere _ il faut en mettre deux) Enfin la derniegravere fonction permet dutiliser les Stock Itemsqui sont un ensemble deacuteleacutements preacutedeacutefinis par GTK+ pour les menus et barres doutils Le seul paramegravetre de cettefonction est le nom de leacuteleacutement et GTK+ se charge dafficher licocircne approprieacutee ainsi que le texte suivant la languechoisie et un raccourci

Cest bien sucircr cette derniegravere fonction que nous allons utiliser et ce le plus souvent possible Voici le code pour creacuteerun tel bouton

maincGtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_QUIT)

Pour obtenir tous les types de stocks items disponibles GtkStockItem

Bien sucircr comme pour la fenecirctre si lon veut voir quelque chose il faut demander agrave GTK+ dafficher notre widget

maincgtk_widget_show (p_button)

Mais pas seulement En effet il faut preacuteciser agrave GTK+ ougrave doit ecirctre afficheacute notre bouton Pour cela la classe GtkWindowest deacuteriveacutee de la classe GtkContainer qui est comme son nom le laisse penser un conteneur pour widget Pourajouter un widget il suffit de faire appel agrave la fonction gtk_container_add

void gtk_container_add (GtkContainer container GtkWidget widget)

Le premier paramegravetre de cette fonction est un GtkContainer or nous souhaitons passer notre fenecirctre qui est unGtkWidget pour ne pas avoir de problegravemes il faut utiliser le systegraveme de macro offert par GTK+ pour transtyper notreGtkWidget en GtkContainer (eh oui en C le polymorphisme a ses limites)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 12 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

maincgtk_container_add (GTK_CONTAINER (p_window) p_button)

Ce meacutecanisme de transtypage permet agrave GTK+ de veacuterifier que notre GtkWidget est bien compatible avec lutilisationque lon souhaite en faire En cas deacutechec GTK+ nous preacutevient en affichant un message dans la console

(gtk_boutonexe1044) Gtk-CRITICAL gtk_container_add assertion `GTK_IS_CONTAINER (container) failed

Pour finir il faut connecter notre bouton pour appeler notre fonction cb_quit lorsque lutilisateur clic dessus (ce quicorrespond agrave leacuteveacutenement clicked)

g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_quit) NULL)

Pour eacuteviter dappeler la fonction gtk_widget_show pour tous les widgets de notreapplication on peut se contenter dun seul appel agrave la fonction gtk_widget_show_all quipermet dafficher tous les widgets contenus dans celui passeacute agrave la fonction

maincinclude ltstdlibhgtinclude ltgtkgtkhgtinclude callbackh

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (cb_quit) NULL)

GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_QUIT) gtk_container_add (GTK_CONTAINER (p_window) p_button) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_quit) NULL)

Affichage de la fenetre principale gtk_widget_show_all (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

III-C - Code source

chapitre3zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 13 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IV - Comment afficher plusieurs widgets

IV-A - Aperccedilu

IV-B - Le problegraveme

Dans la partie preacuteceacutedente nous avons reacuteussi agrave afficher un bouton dans la fenecirctre de notre application Si vous avezessayeacute dajouter un second widget GTK+ agrave ducirc vous reacutepondre poliment

(gtk_boxexe492) Gtk-WARNING Attempting to add a widget with typeGtkButton to a GtkWindow but as a GtkBin subclass a GtkWindow can only containone widget at a time it already contains a widget of type GtkButton

Les plus anglophiles dentre vous auront compris que GTK+ naccepte pas lajout un second widget dans notre fenecirctretout simplement parce quil y en a deacutejagrave un et que la sous classe GtkBin (classe megravere de notre GtkWindow) ne peutcontenir quun seul widget

IV-C - La solutions

Pour contourner ce problegraveme il faut commencer par creacuteer un widget qui accepte den contenir plusieurs autrespour ensuite y ajouter tout ce dont nous avons besoin Pour linstant nous utiliserons quun seul widget (il existetrois classes qui permettent ceci) il sagit des GtkBox Il sagit de la meacutethode que jutilise le plus souvent Ce nestpeut-ecirctre pas la plus simple agrave maicirctriser mais elle extrecircmement souple et puissante Elle consiste agrave creacuteer une boicirctepuis agrave y ajouter les widgets les uns apregraves les autres (soit au deacutebut soit agrave la fin) Il existe deux classes heacuteritant deGtkBox les GtkVBox qui empilent les widgets dans le sens vertical et les GtkHBox qui font de mecircme mais dansle sens horizontal Les fonctions pour manipuler ces deux classes sont les mecircmes seule la fonction pour les creacuteerportent un nom diffeacuterent

GtkWidget gtk_vbox_new (gboolean homogeneous gint spacing)GtkWidget gtk_hbox_new (gboolean homogeneous gint spacing)

Le paramegravetre homogeneous permet de reacuteserver pour chaque widget une zone de taille identique (zone que le widgetnest pas obligeacute de remplir) et spacing permet dajouter une bordure en pixels (espacement autour de la GtkBox)Ensuite il suffit dajouter les diffeacuterents widgets gracircce aux fonctions

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)

Qui ajoutent reacuteciproquement le widget child au deacutebut et agrave la fin de box Le paramegravetre expand permet au widget davoirle plus de place possible (si le paramegravetre homogeneous vaut TRUE cette option a aucun effet) Si plusieurs widgetont ce paramegravetre agrave TRUE ils se partagent de faccedilon eacutegale lespace Loption fill permet au widget de remplir toutlespace qui lui ait reacuteserveacute

Pour reacuteellement comprendre linfluence de ces paramegravetres il faut faire des tests en modifiant un agrave un chaqueparamegravetre et observer les effets dun redimentionnement de la fenecirctre principale

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 14 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Le plus gecircnant avec cette meacutethode cest quil faut jongler entre les GtkHBox et les GtkVBox en les imbriquant pourobtenir le reacutesultat souhaiter nheacutesitez pas agrave utiliser une feuille et un crayon )

Pour en revenir agrave notre eacutediteur de texte nous allons preacuteparer notre application agrave contenir les futurs widgetsNous utilisons un GtkVBox pour lensemble des widgets (il sagit de la boicircte principale qui pourra contenir dautresGtkContainer selon nos besoins)

maincinclude ltstdlibhgtinclude ltgtkgtkhgtinclude callbackh

int main (int argc char argv) GtkWidget p_window = NULL GtkWidget p_main_box = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (cb_quit) NULL)

Creation du conteneur principal p_main_box = gtk_vbox_new (FALSE 0) gtk_container_add (GTK_CONTAINER (p_window) p_main_box)

Creation du bouton Quitter GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_QUIT) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_quit) NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_button FALSE FALSE 0)

Affichage de la fenetre principale gtk_widget_show_all (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

IV-D - Code source

chapitre4zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 15 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

V - Afficher le contenue dun fichier

V-A - Aperccedilu

Cliquez pour agrandir

V-B - Saisir du texte

Les choses seacuterieuses vont commencer il sagit de mettre en place le widget qui va nous permettre dafficher etdeacutediter du texte Il sagit de la classe GtkTextView Gracircce agrave GTK+ la mise en place est toujours aussi simple

mainc GtkWidget p_text_view = NULL Creation de la zone de texte p_text_view = gtk_text_view_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_text_view TRUE TRUE 0)

Comme il sagit de la partie centrale de notre application nous demandons agrave ce quelle prenne le plus de placepossible (gracircce agrave la fonction gtk_box_pack_start)

Puisque nous voulons afficher les boutons en dessous de la zone de texte il faut ajouter ce morceau de code avantcelui creacuteant le bouton

V-C - Ouvrir un fichier

Maintenant nous avons une belle zone de texte il faut la remplir avec le contenu dun fichier Pour ce faire nousallons commencer par ajouter un bouton ouvrir

mainc Creation du bouton Ouvrir GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_OPEN) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_open) p_text_view) gtk_box_pack_start (GTK_BOX (p_main_box) p_button FALSE FALSE 0)

Si vous exeacutecutez le programme maintenant (3) vous remarquerez que les boutons sont ajouteacutes les uns en dessousdes autres ce qui diminue la zone de saisie (avec deux boutons ce nest pas gecircnant mais au bout dune dizaineccedila risque decirctre probleacutematique) Pour pallier ce problegraveme nous allons utiliser un nouveau style de GtkBox lesGtkButtonBox qui sont preacutevus pour contenir des boutons (ccedila tombe plutocirct bien D) Donc pour eacuteviter de diminuerla zone de saisie et comme nous avons de la place en largueur nous allons utiliser un GtkHButtonBox qui va ecirctreinclus dans la p_main_box Voici les modifications agrave effectuer

mainc GtkWidget p_button_box = NULL Creation du conteneur pour les boutons p_button_box = gtk_hbutton_box_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_button_box FALSE FALSE 0)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 16 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc gtk_box_pack_start (GTK_BOX (p_button_box) p_button FALSE FALSE 0) gtk_box_pack_start (GTK_BOX (p_button_box) p_button FALSE FALSE 0)

Maintenant il nous reste plus quagrave creacuteer la fonction cb_open dans le fichier callbackc pour linstant nous nouscontenterons douvrir toujours le mecircme fichier nous verrons plus tard comment laisser le choix agrave lutilisateur

callbackcdefine DEFAULT_FILE mainc

void cb_open (GtkWidget p_widget gpointer user_data) open_file (DEFAULT_FILE GTK_TEXT_VIEW (user_data))

Parametre inutilise (void)p_widget

Vous aurez compris que lon va deacuteleacuteguer tout le travail agrave la fonction open_file qui devra ouvrir le fichier dont le nomest passeacute en premier paramegravetre pour lafficher dans le GktTextView

Jai fait ce choix pour deux raisons le code dune fonction callback peut ecirctre tregraves conseacutequent (surtout si lon souhaitequelle affiche une boicircte de dialogue) et aussi parce que cb_open nest peut ecirctre pas la seule fonction agrave copierun fichier dans un GtkTextView (par exemple lors de la creacuteation dun nouveau fichier lon peut vouloir copier unsquelette de fichier)

Pour copier notre fichier plutocirct que dutiliser la fonction fgets nous allons nous servir de la glib (4) qui proposela fonction

gboolean g_file_get_contents (const gchar filename gchar contents gsize length GError error)

Qui nous renvoit le contenu du fichier nommeacute filename dans le tampon contents Il est possible de reacutecupeacuterer lenombre de caractegraveres copieacutes et retourne TRUE en cas de succegraves sinon FALSE et dans ce cas une structure de typeGError est creacutee pour en savoir plus sur le type derreur rencontreacute

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView else print_warning (Impossible douvrir le fichier sn file_name)

Je pense quun certain nombre dexplications simpose (surtout si je vais trop vite nheacutesitez pas agrave marrecircter )

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 17 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

bull g_return_if_fail est une macro qui peut ecirctre compareacutee agrave assert sauf quelle se contente de sortir de la fonctionsi lexpression passeacutee en paramegravetre est fausse Cest une meacutethode pratique pour veacuterifier la validiteacute desparamegravetres (si la fonction doit retourne une valeur utiliseacute plutocirct g_return_val_if_fail qui prend un secondparamegravetre la valeur agrave retourner)

bull Ensuite on essaie de reacutecupeacuterer le contenu de notre fichier

bull Si cela eacutechoue nous le signalons agrave lutilisateur agrave laide de la fonction print_warning

bull Le type gchar est une redeacutefinition du type char par la glib (il en va de mecircme pour tous les autres types du C)privileacutegiez ces types lorsque vous utilisez des fonctions de cette bibliothegraveques

Mais quest-ce donc cette fonction print_warning Cest une fonction que nous allons creacuteer semblable agrave printf quisignalera agrave lutilisateur quune erreur non critique est survenue Comme nous navons pas encore abordeacute les boicirctesde dialogue pour afficher un message il sagira pour linstant dune simple redeacutefinition de printf Pendant que noussommes dans laffichage des messages nous allons aussi creacuteer deux fonctions print_info et print_error qui vontrespectivement afficher un message dinformation et un message derreur critique (ce qui entraicircne la terminaison duprogramme) tout ceci dans un nouveau fichier errorc

errorhifndef H_ERRORdefine H_ERROR

void print_info (char )void print_warning (char )void print_error (char )

endif not H_ERROR

errorcinclude ltstdarghgtinclude ltstdiohgtinclude ltstdlibhgtinclude errorh

void print_info (char format ) va_list va

va_start (va format) printf (Information ) vprintf (format va) printf (n)

void print_warning (char format ) va_list va

va_start (va format) fprintf (stderr Erreur ) vfprintf (stderr format va) fprintf (stderr n)

void print_error (char format ) va_list va

va_start (va format) fprintf (stderr Erreur fatale ) vfprintf (stderr format va) fprintf (stderr n) exit (EXIT_FAILURE)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 18 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

Pour en finir avec louverture dun fichier il nous reste agrave copier contents dans le GtkTextView En fait le GtkTextViewne gegravere que la forme pour modifier le contenu il faut passer par les GtkTextBuffer Commenccedilons donc par reacutecupeacutererce fameux GtkTextBuffer

callbackc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (p_text_view)

Et pour finir on utilise la fonction

void gtk_text_buffer_insert (GtkTextBuffer buffer GtkTextIter iter const gchar text gint len)

Reacutecapitulons buffer est le GtkTextBuffer que lon vient de reacutecupeacuterer text cest le texte agrave afficher et len la taille dece dernier (ou -1 sil sagit dune chaicircne de caractegraveres au sens du langage C)

Mais quest-ce donc ce GtkTextIter On peut voir cela comme un curseur virtuel qui indique la position agrave laquelleeffectuer linsertion de texte dans le GtkTextBuffer (5) Allons voir ce que la documentation peut nous apprendreagrave leur sujet (6)

typedef struct GtkTextIter is an opaque datatype ignore all these fields Initialize the iter with gtk_text_buffer_get_iter_ functions GtkTextIter

Voilagrave on a notre solution suffit de rechercher les fonctions commenccedilant par gtk_text_buffer_get_iter_ voici la liste

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)

La fonction gtk_text_buffer_get_iter_at_line fait parfaitement laffaire

callbackc GtkTextIter iter

gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1)

Cependant si vous ne voulez pas avoir de problegravemes avec le codage des caractegraveres il vaut mieux convertir le codagelocal vers utf8 Voici le reacutesultat final

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 19 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gchar utf8 = NULL GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_text_buffer_insert (p_text_buffer ampiter utf8 -1) g_free (utf8) utf8 = NULL

V-D - La petite touche finale

Pour finir cette laborieuse partie sur une petite touche estheacutetique nous allons demander agrave GTK+ de nous lancerlapplication en plein eacutecran Pour se faire il suffit dajouter lors de la creacuteation de la fenecirctre principale

maincgtk_window_maximize (GTK_WINDOW (p_window))

On peut mecircme se permettre une pointe dexcentriciteacute en modifiant le titre de notre fenecirctre

maincgtk_window_set_title (GTK_WINDOW (p_window) Editeur de texte en GTK+)

V-E - Code source

chapitre5zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 20 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VI - Choisir un fichier

VI-A - Aperccedilu

Cliquez pour agrandir

VI-B - Utilisation dun GtkFileChooserFile

Jusquagrave preacutesent lutilisateur navait pas le choix quant au fichier agrave ouvrir heureusement GTK+ vient agrave notre aide gracircceau widget GtkFileChooserFile qui est tout simplement une boicircte de dialogue qui propose agrave lutilisateur de seacutelectionnerun fichier dans son arborescence disque

Commenccedilons par creacuteer notre boicircte de dialogue dans la fonction cb_open

callbackcvoid cb_open (GtkWidget p_widget gpointer user_data) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Ouvrir un fichier NULL GTK_FILE_CHOOSER_ACTION_OPEN GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_OPEN GTK_RESPONSE_ACCEPT NULL)

Cette fonction neacutecessite le titre de la boicircte de dialogue une fenecirctre parente le type daction (ici on souhaite ouvrir unfichier GTK+ autorisera lutilisateur agrave seacutelectionner uniquement les fichiers existants) Pour finir il sagit dun couple devaleurs GTK_STOCK_ITEMGTK_STOCK_RESPONSE qui permet de creacuteer un bouton utilisant le stock ID speacutecifieacuteet lorsque celui-ci est cliqueacute la fonction servant agrave lancer la boicircte de dialogue retournera le reacuteponse ID correspondantIl existe une seacuterie de valeurs deacutefinies par GTK+ quil est conseilleacute dutiliser

typedef enum GTK returns this if a response widget has no response_id or if the dialog gets programmatically hidden or destroyed GTK_RESPONSE_NONE = -1

GTK wont return these unless you pass them in as the response for an action widget They are for your convenience GTK_RESPONSE_REJECT = -2 GTK_RESPONSE_ACCEPT = -3

If the dialog is deleted GTK_RESPONSE_DELETE_EVENT = -4

These are returned from GTK dialogs and you can also use them yourself if you like GTK_RESPONSE_OK = -5 GTK_RESPONSE_CANCEL = -6 GTK_RESPONSE_CLOSE = -7 GTK_RESPONSE_YES = -8

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 21 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GTK_RESPONSE_NO = -9 GTK_RESPONSE_APPLY = -10 GTK_RESPONSE_HELP = -11 GtkResponseType

Nous indiquons la fin des couples stock idreacuteponse id avec la valeur NULL

Une fois la boicircte de dialogue creacuteee on demande agrave GTK+ de lafficher gracircce agrave la fonction gtk_dialog_run puis onreacutecupegravere sa valeur de retour qui correspond au bouton cliqueacute par lutilisateur

callbackc if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

Ici ce qui nous inteacuteresse cest lorsque que lutilisateur clique sur le bouton ouvrir (donc gtk_dialog_run renvoieGTK_RESPONSE_ACCEPT) dans ce cas il nous suffit de reacutecupeacuterer le nom du fichier seacutelectionneacute puis de louvrir

callbackc gchar file_name = NULL

file_name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) open_file (file_name GTK_TEXT_VIEW (user_data)) g_free (file_name) file_name = NULL

Pour finir dans tous les cas on noublie pas de deacutetruire la boicircte de dialogue

callbackc gtk_widget_destroy (p_dialog)

Et voilagrave le travail lutilisateur peut ouvrir le fichier quil souhaite

VI-C - Code source

chapitre6zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 22 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VII - Interlude

Avant daller plus loin dans lameacutelioration de linterface de notre eacutediteur il est neacutecessaire de modifier sonfonctionnement interne (ne vous inquieacutetez je nai pas dit chambouler) en effet souvenez-vous dans lintroduction jaieacutevoqueacute la possibiliteacutes douvrir plusieurs documents gracircce agrave un systegraveme donglets Pour cela il faut sauvegarder lesproprieacuteteacutes de chaque document ouvert Pris agrave temps ce genre de modification nest pas trop lourde mais si nousattendons cela risque de devenir un vrai casse tecircte

Pour cela nous allons utiliser une structure de donneacutee pour chaque document ouvert qui devra garder en meacutemoirele chemin complet du fichier (ou NULL si le document nest pas encore sauvegarder) sil agrave eacutetait modifier depuis laderniegravere sauvegarde et le GtkTextView qui sert agrave son affichage Voici donc la structure qui va nous servir

documenthtypedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

Sachant que nous serons ameneacute agrave stocker plusieurs occurrences de cette structure il serait bon de reacutefleacutechir degravesmaintenant agrave la structure de donneacutee agrave utiliser pour les stocker La premiegravere ideacutee qui vient agrave lesprit est un tableaualloueacute dynamiquement cependant lutilisateur peut souhaiter fermer un document qui se trouve au milieu on estalors obligeacute de deacutecaler toutes les cellules en amont Dans ce cas il parait naturel dutiliser une liste chaicircneacutee Parchance la glib propose une bibliothegraveque de gestion des listes chaicircneacutees cela nous fera gagner du temps le momentvenu Pour linstant on se contente de creacuteer une structure de donneacutees qui contiendra tous les documents ouverts(stockeacutee dans une GList) et un pointeur sur le document actif (actuellement comme nous navons quun documentouvert en mecircme temps on manipulera uniquement ce pointeur)

documenthtypedef struct GList tous document_t actif docs_t

Maintenant se pose le problegraveme de savoir comment transmettre cette structure On pourrait se servir du paramegravetreuser_data preacutesent dans toutes les fonctions callback mais certaines fonctions utilise deacutejagrave ce paramegravetre (la fonctioncb_open par exemple) il faudrait creacuteer un champs suppleacutementaire dans notre structure documents_s Une solutionplus simple est de creacuteer une variable globale agrave lensemble du programme Ceux qui passe reacuteguliegraverement sur le forumC savent que cest fortement deacuteconseilleacute mais ici nous nous trouvons dans lune des rares exceptions agrave la regravegle Detoute faccedilon cela revient au mecircme que de passer ladresse de notre structure agrave toutes les fonctions callback Nousdeacutefinissons donc un nouveau fichier den-tecircte

documenthifndef H_DOCUMENTdefine H_DOCUMENT

include ltgtkgtkhgt

typedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 23 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

documenthtypedef struct GList tous document_t actif docs_t

extern docs_t docs

endif not H_DOCUMENT

Et dans le fichier mainc

maincinclude documenth

docs_t docs = NULL NULL

Pour linstant la seule fonction qui modifie leacutetat dun document est la fonction open_file il faut donc inclure documenthdans callbackc et modifier leacutegegraverement la fonction pour enregistrer le document ouvert

callbackc if (g_file_get_contents (file_name ampcontents NULL NULL)) Pour linstant il faut allouer la memoire par la suite on modifira simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = g_strdup (file_name) Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = p_text_view Le document vient detre ouvert il nest donc pas modifie docsactif-gtsauve = TRUE

Ne soyez pas choqueacute si je ne teste pas le retour de la fonction g_malloc pour veacuterifier quilnest pas NULL En effet cette derniegravere met fin agrave lapplication si lallocation eacutechoue

VII-A - Code source

chapitre7zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 24 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VIII - Sauvegarder les modification

VIII-A - Aperccedilu

Cliquez pour agrandir

VIII-B - Enregistrer

Avant de pouvoir sauvegarder un document il faut quil soit modifieacute Comment savoir que le contenu du fichier a eacuteteacutemodifier Gracircce au signal changed du GtkTextBuffer que nous interceptons gracircce agrave la fonction cb_modifie

mainc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (p_text_view)) g_signal_connect (G_OBJECT (p_text_buffer) changed G_CALLBACK (cb_modifie) NULL)

Cette derniegravere modifie simplement le champ sauve du document

callbackcvoid cb_modifie (GtkWidget p_widget gpointer user_data) if (docsactif) docsactif-gtsauve = FALSE

Pour la sauvegarde il faut distinguer deux cas soit il sagit de la premiegravere sauvegarde du fichier il faut alors demanderle nom du fichier agrave lutilisateur (cela ressemble fortement agrave louverture dun fichier) soit le fichier est deacutejagrave preacutesent surle disque il suffit de remplacer son contenu par celui du GtkTextViewer Nous avons convenu quun fichier qui neacutetaitpas encore enregistreacute avait sa proprieacuteteacute chemin agrave NULL

Bien sucircr cela na lieu que si un fichier est ouvert et quil a eacuteteacute modifieacute depuis sa derniegravere sauvegarde

callbackcvoid cb_save (GtkWidget p_widget gpointer user_data) if (docsactif) if (docsactif-gtsauve) Le fichier na pas encore ete enregistre if (docsactif-gtchemin) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Sauvegarder le fichier NULL GTK_FILE_CHOOSER_ACTION_SAVE GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_SAVE GTK_RESPONSE_ACCEPT NULL) if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 25 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc docsactif-gtchemin = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) gtk_widget_destroy (p_dialog) Soit le fichier a deja ete enregistre soit lutilisateur vient de nous fournir son nouvel enplacement on peut donc lenregistrer if (docsactif-gtchemin) else print_warning (Aucun document ouvert)

Il nous reste plus quagrave reacutecupeacuterer le contenu du GtkTextViewer et le copier dans le fichier chemin sans oublier dereconvertir le texte dans le codage local

callbackc FILE fichier = NULL

fichier = fopen (docsactif-gtchemin w) if (fichier) gchar contents = NULL gchar locale = NULL GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) contents = gtk_text_buffer_get_text (p_text_buffer ampstart ampend FALSE) locale = g_locale_from_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL fprintf (fichier s locale) g_free (locale) locale = NULL fclose (fichier) fichier = NULL docsactif-gtsauve = TRUE else print_warning (Impossible de sauvegarder le fichier s docsactif-gtchemin)

Le dernier paramegravetre de la fonction gtk_text_buffer_get_text est mis agrave FALSE car nous ne voulons pas enregistrerles caractegraveres invisibles preacutesent dans le GtkTextBuffer Ces caractegraveres servent agrave mettre en forme le texte (taillecouleur) nous pourrions creacuteer un nouveau format de fichier pour enregistrer la mise en forme

VIII-C - Enregistrer sous

Pour enregistrer notre document sous un autre nom il suffit de faire croire agrave cb_save que le document na pas encoreeacutetait enregistreacute tout simplement en changeant chemin agrave NULL et sauve agrave FALSE

callbackcvoid cb_saveas (GtkWidget p_widget gpointer user_data)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 26 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (docsactif) document_t tmp = docsactif

docsactif-gtchemin = NULL docsactif-gtsauve = FALSE cb_save (p_widget user_data) if (docsactif-gtsauve) (docsactif) = tmp else print_warning (Aucun document ouvert)

Il ne faut pas oublier que lutilisateur peut annuler lenregistrement de ce fait nous sauvegardons leacutetat du documentet si la sauvegarde na pas eu lieu on le restaure

VIII-D - Code source

chapitre8zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 27 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IX - Creacuteer un nouveau document

IX-A - Aperccedilu

Cliquez pour agrandir

IX-B - Nouveau fichier

Maintenant que lutilisateur peut ouvrir et fermer un fichier il est inteacuteressant de lui donner la possibiliteacute den creacuteerun nouveau Je ne reviens pas sur la creacuteation du bouton (ccedila devrait deacutejagrave ecirctre fait D) passons directement agrave lafonction cb_new

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) Pour linstant il faut allouer la memoire par la suite on modifiera simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = NULL Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = GTK_TEXT_VIEW (user_data) Le document vient detre creer il nest donc pas modifie docsactif-gtsauve = TRUE gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Je ne sais pas vous mais pour ma part jai fait un copiercoller de la fonction open_file Et oui ouvrir un document peutse reacutesumer agrave creacuteer un document vide puis remplir le GtkTextView avec le fichier souhaiteacute On peut donc simplifiernotre fonction open_file ainsi

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

cb_new (NULL p_text_view) gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE) p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1) Nous sommes obliges de remetre sauve a TRUE car linsertion du contenu du fichier dans le GtkTextView a appele cb_modfie docsactif-gtsauve = TRUE else print_warning (Impossible douvrir le fichier sn file_name)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 28 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc

Cest beau la factorisation du code Par contre nous sommes obligeacutes de remettre sauve agrave TRUE car nous avonsmodifieacute le GtkTextBuffer

IX-C - Code source

chapitre9zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 29 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

X - Fermer

X-A - Aperccedilu

Cliquez pour agrandir

X-B - Fermer un fichier

Maintenant que nous allouons de la meacutemoire il faut la libeacuterer agrave un endroit Logiquement cela va ecirctre fait agrave la fermeturedu document en guise dexercice je vous laisse creacuteer le bouton dans notre boicircte agrave bouton

Allez je vous aide le stock id correspondant est GTK_STOCK_CLOSE

Voilagrave maintenant si tout cest bien passeacute vous devriez ecirctre arriveacute dans le fichier callbackc avec quelque choseressemblant agrave

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data)

Lorsque lon ferme un document il faut vider le GtkTextView (avec les onglets on se contentera de le supprimer)pour cela il faut reacutecupeacuterer le deacutebut et la fin du GtkTextBuffer et demander agrave GTK+ de supprimer tout ce qui ce trouveentre les deux iteacuterateurs

callbackc Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) gtk_text_buffer_delete (p_text_buffer ampstart ampend) else print_warning (Aucun document ouvert)

Bien sucircr il ne faut pas oublier de libeacuterer la meacutemoire

callbackc g_free (docsactif-gtchemin) docsactif-gtchemin = NULL docsactif-gtp_text_view = NULL g_free (docsactif) docsactif = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 30 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour symboliser la fermeture dun document nous deacutesactivons le GtkTextView lors de la fermeture (ne pas oublierde le faire aussi dans mainc)

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) FALSE)

Et nous le reacuteactivons lors de louverture si celle si reacuteussie

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Lorsque lutilisateur quitte lapplication il faut bien sucircr fermer le document sil y en a un ouvert

void cb_quit (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data) gtk_main_quit()

Et aussi lorsquil creacuteeacute un nouveau document (et par conseacutequent lorsquil ouvre un fichier puisque lon fait appel agravecb_new)

void cb_new (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data)

X-C - Enregistrer avant de fermer

Si le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde geacuteneacuteralement le programme le signale agrave lutilisateur etlui propose de sauvegarder ou dannuler la fermeture Pour se faire nous devons modifier la fonction cb_close avantde fermer le document nous allons afficher une boicircte de dialogue

Pour creacuteer une boicircte de dialogue simplement il existe la classe GtkDialog et comme nous avons besoin de boutons(pour que lutilisateur fasse son choix) nous allons creacuteer notre boicircte avec la fonction

GtkWidget gtk_dialog_new_with_buttons (const gchar title GtkWindow parent GtkDialogFlags flags const gchar first_button_text )

Nous retrouvons les mecircmes options que pour le GtkFileChooserDialog mis agrave part option du type GtkDialogFlags

typedef enum GTK_DIALOG_MODAL = 1 ltlt 0 appel gtk_window_set_modal (win TRUE) GTK_DIALOG_DESTROY_WITH_PARENT = 1 ltlt 1 appel gtk_window_set_destroy_with_parent () GTK_DIALOG_NO_SEPARATOR = 1 ltlt 2 Pas de barre de separation au dessus des boutons GtkDialogFlags

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 31 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Nous nous contenterons de rendre notre fenecirctre modale (7)

Pour avoir accegraves agrave notre fenecirctre principale nous ajoutons un champs p_main_window agrave notre structure globaledocs_t que nous initialisons dans la fonction main

mainc docsp_main_window = GTK_WINDOW (p_window)

Il nous reste plus qua creacuteer notre boicircte de dialogue avec trois boutons Oui Non Annuler

callbackc if (docsactif-gtsauve) GtkWidget p_dialog = NULL

p_dialog = gtk_dialog_new_with_buttons (Sauvegarder docsp_main_window GTK_DIALOG_MODAL GTK_STOCK_YES GTK_RESPONSE_YES GTK_STOCK_NO GTK_RESPONSE_NO GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL NULL)

Nous obtenons donc une structure de type GtkDialog

typedef struct GtkWidget vbox GtkWidget action_area GtkDialog

Nous remarquons que cette structure contient deux membres qui permettent dacceacuteder agrave une GtkBox ougrave nous allonsajouter le contenu de la fenecirctre et agrave la partie contenant les boutons

Ensuite la construction de la fenecirctre est identique agrave celle de la fenecirctre principale ici nous nous contenterons dajouterun GtkLabel

callbackc GtkWidget p_label = NULL p_label = gtk_label_new (Voulez-vous sauvegarder les modifications ) gtk_box_pack_start (GTK_BOX (GTK_DIALOG (p_dialog)-gtvbox) p_label TRUE TRUE 0)

Une fois notre fenecirctre precircte il suffit de faire appel agrave la fonction gtk_dialog_run qui va afficher notre GtkDialog et nousretourner le reacuteponse id correspondant au bouton cliqueacute par lutilisateur

callbackc switch (gtk_dialog_run (GTK_DIALOG (p_dialog))) case GTK_RESPONSE_YES cb_save (p_widget user_data) break case GTK_RESPONSE_NO break case GTK_RESPONSE_CANCEL gtk_widget_destroy (p_dialog) return break

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 32 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc gtk_widget_destroy (p_dialog)

Si lutilisateur clique sur non on ne fait rien (le document sera simplement fermeacute) sur oui on enregistre avant defermer et pour finir sil annule on quitte la fonction

X-D - Code source

chapitre10zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 33 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XI - Les barres de deacutefilement

XI-A - Aperccedilu

Cliquez pour agrandir

XI-B - Ajouter des barres de deacutefilement

Apregraves le dernier chapitre quelque peu laborieux voici une partie plus simple mais qui va rendre notre applicationplus pratique En effet si vous avez essayeacute douvrir un fichier de grande taille vous avez pu remarquer que pourpouvoir lire la fin du fichier il fallait utiliser les touches du clavier pas tregraves convivial

Pour rendre la navigation plus aiseacutee on utilise des barres de deacutefilement

mainc GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_scrolled_window TRUE TRUE 0)

Creation de la zone de texte gtk_container_add (GTK_CONTAINER (p_scrolled_window) p_text_view)

Le constructeur de notre GtkScrolledWindow prend en argument deux GtkAdjustment qui permettent de deacutefinirdiffeacuterentes proprieacuteteacutes de la barre de deacutefilement (taille dune page la position de deacutepart) nous laissons GTK+ faireen passant NULL

Cest un bon deacutebut mais estheacutetiquement on peut faire mieux mecircme sil nest pas utile davoir une barre de deacutefilementelle est quand mecircme afficheacutee On peut demander agrave GTK+ de les afficher que si cela est neacutecessaire

mainc gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC)

En fait nous avons de la chance car la classe GtkTextView fait partie des widget qui supporte de faccedilon native les barresde deacutefilement Comment le savoir Ce genre de widget possegravede une ou deux proprieacuteteacutes de type GtkAdjustment (unepour la barre verticale lautre pour la barre horizontale) Actuellement seulement trois classes en sont capables lesGtkTextView les GtkTreeView et les GtkLayout

Comment faire pour les autres widgets Il faut passer par une classe adaptateur GtkViewport afin de creacuteer lesGtkAdjustment

XI-C - Code source

chapitre11zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 34 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XII - Les menus

XII-A - Aperccedilu

Cliquez pour agrandir

XII-B - Creacuteation du menu

Pour simplifier nous avons utiliseacute des boutons pour permettre agrave lutilisateur de creacuteer un document ouvrir un fichierMais il est plus courant dutiliser un menu pour afficher ces options GTK+ propose trois maniegraveres de creacuteer un menu

bull GtkItemFactory cette meacutethode est obsolegravete depuis la version 24 de GTK+

bull GtkUIManager cest ce quon appel une usine agrave gaz pour en savoir plus vous pouvez vous reporter aututoriel Utilisation de GtkUIManager

bull GtkMenu cest ce widget que nous allons eacutetudier il permet de creacuteer un menu manuellement (agrave lopposeacute deGtkUIManager)

Un menu selon GTK+ est composeacute de plusieurs eacuteleacutements

bull GtkMenuBar la barre de menu elle-mecircme

bull GtkMenu la partie deacuteroulante qui contient les diffeacuterents eacuteleacutements

bull GtkMenuItem cest sur ce widget que lutilisateur clique pour lancer une action

Pour commencer faisons linventaire de ce que nous avons besoin

bull Un GtkMenuBar qui sert de base au menu

bull Un GtkMenu pour commencer nous nous aurons dun menu Fichier

bull Six GtkMenuItem pour remplacer nos six boutons

Commenccedilons par la creacuteation du menu nous mettons ce code dans un nouveau fichier dont seul la fonction menu_newsera accessible

menucGtkMenuBar menu_new (gpointer user_data) GtkWidget p_menu_bar = NULL

p_menu_bar = gtk_menu_bar_new () return GTK_MENU_BAR (p_menu_bar)

Le paramegravetre user_data nous servira lors de la connexion des callbacks (nous en avons besoin pour les fonctionscb_new et cb_open)

Ensuite nous allons creacuteer notre sous menu Fichier

menuc Menu Fichier

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 35 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

menuc GtkWidget p_menu = NULL GtkWidget p_menu_item = NULL

p_menu = gtk_menu_new () p_menu_item = gtk_menu_item_new_with_mnemonic (_Fichier) gtk_menu_item_set_submenu (GTK_MENU_ITEM (p_menu_item) p_menu) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu_bar) p_menu_item) return GTK_MENU_BAR (p_menu_bar)

Un sous menu est en fait un GtkMenuItem auquel on assigne un GtkMenu Il faut bien sucircr terminer la creacuteation dusous-menu en lajoutant agrave la barre de menu

Pour finir nous creacuteons les eacuteleacutements du menu les GtkItemMenu Il existe plusieurs types deacuteleacutements (comparableaux diffeacuterents types de bouton) pour commencer nous nutiliserons que le type de base Comme cette opeacuteration estreacutepeacutetitive nous allons creacuteer une fonction pour le faire

menucstatic void menu_item_new (GtkMenu p_menu const gchar title GCallback callback gpointer user_data) GtkWidget p_menu_item = NULL

p_menu_item = gtk_menu_item_new_with_mnemonic (title) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu) p_menu_item) g_signal_connect (G_OBJECT (p_menu_item) activate callback user_data)

Pour permettre agrave lutilisateur dacceacuteder aux diffeacuterents eacuteleacutements du menu agrave laide de la touche ltAltgt nous utilisonsdes mneacutemoniques par exemple pour quitter leacutediteur il suffit de faite Alt+F puis Q Et voici le code pour creacuteer nossix eacuteleacutements du menu

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau G_CALLBACK (cb_new) user_data) menu_item_new (GTK_MENU (p_menu) _Ouvrir G_CALLBACK (cb_open) user_data) menu_item_new (GTK_MENU (p_menu) _Enregistrer G_CALLBACK (cb_save) user_data) menu_item_new (GTK_MENU (p_menu) Enregistrer _sous G_CALLBACK (cb_saveas) user_data) menu_item_new (GTK_MENU (p_menu) _Fermer G_CALLBACK (cb_close) user_data) menu_item_new (GTK_MENU (p_menu) _Quitter G_CALLBACK (cb_quit) user_data)

Voilagrave notre menu est creacuteeacute il nous reste plus quagrave linteacutegrer agrave notre fenecirctre

mainc gtk_box_pack_start (GTK_BOX (p_main_box) GTK_WIDGET (menu_new (p_text_view)) FALSE FALSE 0)

Le problegraveme cest que nous avons besoin de passer le GtkTextView lors de la creacuteation du menu (qui est utiliseacute par lesfonctions cb_new et cb_open) or celui-ci est creacuteeacute apregraves le menu (puisque nous creacuteons les widgets dans lordre ougrave ilfaut les inteacutegrer agrave linterface (8) ) nous devons creacuteer le GtkTextView (seul lappel agrave gtk_text_view_new est deacuteplaceacute)

XII-C - Code source

chapitre12zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 36 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIII - Les barres doutils

XIII-A - Aperccedilu

Cliquez pour agrandir

XIII-B - Creacuteation dune barre doutils

La creacuteation dune barre doutils ressemble fort agrave celle dun menu en plus simple puisquil ny a pas de sous menu on creacutee notre barre doutils (gtk_toolbar_new) puis les eacuteleacutements de la barre pour cela on utilise des boutons(gtk_tool_button_new_from_stock) que lon inseacutere dans la barre (gtk_toolbar_insert) Pas conseacutequent notre fichierbarreoutilsc ressemble agrave menuc

barreoutilscinclude ltgtkgtkhgtinclude callbackhinclude barreoutilsh

static void toolbar_item_new (GtkToolbar const gchar GCallback gpointer)

GtkToolbar toolbar_new (gpointer user_data) GtkWidget p_toolbar = NULL

p_toolbar = gtk_toolbar_new () toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_NEW G_CALLBACK (cb_new) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_OPEN G_CALLBACK (cb_open) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE G_CALLBACK (cb_save) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE_AS G_CALLBACK (cb_saveas) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_CLOSE G_CALLBACK (cb_close) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_QUIT G_CALLBACK (cb_quit) user_data) return GTK_TOOLBAR (p_toolbar)

static void toolbar_item_new (GtkToolbar p_toolbar const gchar stock_id GCallback callback gpointer user_data) GtkToolItem p_tool_item = NULL

p_tool_item = gtk_tool_button_new_from_stock (stock_id) g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data) gtk_toolbar_insert (p_toolbar p_tool_item -1)

Le code nest pas complet car lorsque jexeacutecute le programme GTK+ affiche en plus des icocircnes le texte sous lesboutons Pour modifier cela il suffit dajouter une ligne de code

barreoutilsc gtk_toolbar_set_style (GTK_TOOLBAR (p_toolbar) GTK_TOOLBAR_ICONS)

Pourquoi gtk_tool_button_new_from_stock retourne un GtkToolItem et non un GtkWidgetcomme nous avons eacuteteacute habitueacute jusquagrave preacutesent Il sagit dune bizarrerie de GTK+ dontje ne connais pas la raison

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 37 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour anticiper un changement dinterface (dans GTK+ 30 peut ecirctre ) nous aurions pueacutecrire

Gtkwidget p_tool_item = NULL

p_tool_item = GTK_WIDGET (gtk_tool_button_new_from_stock (stock_id))g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data)gtk_toolbar_insert (p_toolbar GTK_TOOL_ITEM (p_tool_item) -1)

XIII-C - Code source

chapitre13zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 38 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIV - Les racourcis clavier

XIV-A - Aperccedilu

Cliquez pour agrandir

XIV-B - Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mneacutemoniques ces derniers permettent dacceacuteder agrave un eacuteleacutementseacutequentiellement alors que les raccourcis appellent une fonction si lutilisateur appuie simultaneacutement sur une ouplusieurs touches (geacuteneacuteralement de la forme ltModificateurgtTouche ougrave Modificateur repreacutesente les touches ShiftAlt et Control) Ce raccourci peut ecirctre attacheacute agrave un eacuteleacutement du menu mais ceci nest pas obligatoire

Les raccourcis sont regroupeacutes en groupe dans un GtkAccelGroup quil faut commencer par creacuteer

raccourciscinclude ltgtkgtkhgtinclude callbackhinclude raccourcish

GtkAccelGroup accel_group_new (gpointer user_data) GtkAccelGroup p_accel_group = NULL

p_accel_group = gtk_accel_group_new () return p_accel_group

Vous commencez agrave avoir lhabitude de cette organisation nous allons donc creacuteer une fonction qui va se chargerdajouter un raccourci au groupe

raccourciscstatic void accelerator_new (GtkAccelGroup p_accel_group const gchar accelerator const gchar accel_path GCallback callback gpointer user_data) guint key GdkModifierType mods GClosure closure = NULL

gtk_accelerator_parse (accelerator ampkey ampmods) closure = g_cclosure_new (callback user_data NULL) gtk_accel_group_connect (p_accel_group key mods GTK_ACCEL_VISIBLE closure) gtk_accel_map_add_entry (accel_path key mods)

La fonction gtk_accelerator_parse permet de deacutecomposer une chaicircne de caractegraveres de la forme ltControlgtF1 ouencore ltAltgtA en numeacutero de touche et modificateur

En plus des touches pour creacuteer un raccourci clavier nous avons besoin dune fonction agrave appeler lorsque lutilisateurappuie sur les touches speacutecifieacutees gtk_accel_group_connect attend une fonction du type GClosure regardons ladocumentation de gobject pour savoir agrave quoi cela correspond

typedef struct

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 4 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

I - Introduction

I-A - But de ce tutoriel

Pour vous initier aux joies de la programmation dinterfaces graphiques plutocirct que de faire un catalogue de toutesles fonctions de la bibliothegraveque ce qui serait long et vite ennuyeux je vous propose de construire pas agrave pas uneapplication un eacutediteur de texte Pas un simple eacutediteur de texte histoire de faire le tour des possibiliteacutes de GTK+nous allons y ajouter pas agrave pas les fonctionnaliteacutes suivantes

bull Creacuteation ouverture enregistrement de fichiers textes

bull Possibiliteacute douvrir plusieurs fichiers gracircce agrave une navigation par onglets

bull Ouverture rapide dun fichier gracircce agrave une liste de fichiers

Rien dimpressionnant par rapport agrave un traitement de texte mais plus eacutevolueacute et plus pratique quun simple eacutediteurde texte Ce tutoriel est organiseacute de faccedilon agrave ajouter une nouvelle fonctionnaliteacute agrave chaque eacutetape tout en apprenantagrave maicirctriser un ou plusieurs eacuteleacutements de GTK+

Comme je viens de le dire il nest pas question de faire un catalogue de la bibliothegravequecependant avant dutiliser un nouveaux type de widget jen ferai une bregraveve descriptionqui pourra vous servir de pense becircte lors de vos futurs deacuteveloppements Cette descriptioncomportera un aperccedilu pour les widgets graphiques sa hieacuterarchie dheacuteritage ses fonctionsde creacuteations (constructeurs) les fonctions les plus utiliseacutees et les signaux importants dela classe

I-B - Connaissances requises

Le but de ce tutorial est dapprendre agrave maicirctriser GTK+ en partant de zeacutero ou presque en effet avant de vouloir creacuteerune interface graphique il vaut mieux bien connaicirctre le langage C en mode console Pour cela je vous renvoie aucours de la rubrique C

I-C - Quelques mots sur GTK+

I-C-1 - Historique

GTK+ ou the GIMP Toolkit eacutetait agrave lorigine une boicircte agrave outils pour les deacuteveloppeurs du logiciel the GIMP (the GNUImage Manipulation Program) qui comme son nom lindique est un logiciel de manipulation dimages rattacheacute auprojet GNU Au vu de limportance de cette boicircte agrave outils GTK+ a eacuteteacute deacutetacheacute de the GIMP en septembre 1997Depuis il existe deux versions GTK+ 10 et GTK+ 20 versions qui ne sont pas totalement compatibles cependantla premiegravere est encore utiliseacutee dans certaines applications tel que dans le domaine de lembarqueacute du fait de sacomplexiteacute moindre Il est bien eacutevident que cest la seconde version qui est la plus utiliseacutee elle est agrave lorigine denombreux projets tel que le gestionnaire de fenecirctre GNOME (GNU Network Object Model Environment) La derniegravereversion en date est la 281 annonceacutee le 24 Aoucirct 2005

I-C-2 - Structure

Comme preacuteciseacute preacuteceacutedemment GTK+ est une boicircte agrave outils et en tant que tel elle est constitueacutee de plusieursbibliothegraveques indeacutependantes deacuteveloppeacutees par leacutequipe de GTK+

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 5 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

bull La GLib propose un ensemble de fonctions qui couvrent des domaines aussi vastes que les structures dedonneacutees la gestion des threads et des processus de faccedilon portable ou encore un analyseur syntaxique pourles fichiers XML et bien dautre

bull Pango il sagit de la bibliothegraveque daffichage et de rendue de textes

bull ATK

La bibliothegraveque GTK+ en elle-mecircme utilise une approche orienteacutee objet et repose sur plusieurs couches

bull GObject il sagit de la base de limpleacutementation des objets pour la POO

bull GDK bibliothegraveque graphique de bas niveau

bull GTK+ la bibliothegraveque GTK+ elle-mecircme baseacutee sur lutilisation de widgets (1)

Cest bien sucircr cette derniegravere qui nous inteacuteresse ici mais la glib nous sera aussi dune grande aide

I-C-3 - Pourquoi utiliser GTK+

Effectivement pourquoi choisir dutiliser GTK+ plutocirct quune autre bibliothegraveque pour reacutealiser une interface graphiqueVoici quelques arguments

bull GTK+ est sous licence libre LGPL vous pouvez donc lutiliser pour deacutevelopper des programmes libres oucommerciaux

bull La portabiliteacute GTK+ est disponible sur un grand nombre de systegravemes dont Windows Linux Unix et MacOSX

bull GTK+ est deacuteveloppeacutee en C et pour le langage C cependant elle est disponible pour dautres langages telsque Ada C++ (gracircce agrave gtkmm) Java Perl PHP Python Ruby ou plus reacutecemment C

I-D - Installation

I-D-1 - Windows

Pour pouvoir exeacutecuter une application utilisant GTK+ il faut commencer par installer les binaires Pour faciliter leurinstallation il existe un installeur

Si vous utilisez the Gimp utilisez les runtimes proposeacutees sur le sitehttpwwwgimp-winorg

Pour deacutevelopper une application il faut les bibliothegraveques ainsi que les fichiers den-tecircte disponibles sur gtkorg Pourceux qui utilisent CodeBlocks voici la meacutethode agrave suivre Installation de

I-D-2 - Linux

Sous Linux vous disposez sucircrement dun systegraveme de paquets Il vous faudra installer deux paquets le premiercontenant les fichiers permettant dexeacutecuter des programmes utilisant GTK+ le second paquet contient les fichiersneacutecessaires au deacuteveloppement

Une fois linstallation reacuteussie compilez agrave laide de la commande

gcc -Werror -Wall -W -O2 -ansi -pedantic `pkg-config --cflags --libs gtk+-20` c

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 6 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Tous les codes de ce tutoriel ont eacuteteacute testeacutes sous Linux Debian et Windows XP avecCodeBlocks

I-E - La philosophie GTK+

Voici quelques choix qui ont eacuteteacute faits par leacutequipe de deacuteveloppement de GTK+

bull Les noms de fonctions sont de la forme gtk_type_du_widget_action ceci rend les noms des fonctions tregravesexplicites en contre partie ils peuvent ecirctre tregraves longs

bull Tous les objets manipuleacutes sont des GtkWidget pour que GTK+ veacuterifie quil sagit du bon type dobjet lors delappel agrave une fonction chaque type de widget possegravede une macro de la forme GTK_TYPE_DU_WIDGET agraveutiliser pour transtyper vos widgets

bull La gestion des eacuteveacutenements qui modifient le comportement de lapplication (clique de souris pression dunetouche du clavier) se fait gracircce agrave lutilisation de fonctions de rappel (callback) Pour cela on connecte leswidgets agrave des fonctions qui seront appeleacutees lorsque leacuteveacutenement survient

I-F - Quelques notions de POO

La POO ou Programmation Orienteacutee Objet est un mode de programmation baseacutee sur des objets GTK+ utilisant ceprincipe (2) je vais vous en expliquer les principes de bases

Plutocirct que le deacuteroulement du programme soit reacutegie par une suite dinstruction en POO il est reacutegi par la creacuteationlinteraction et la destruction dobjets en reacutesumeacute la vie des objets qui le composent Un objets est une entiteacute (leparallegravele avec la vie courante est simple un objet pourrait ecirctre un ordinateur) en C on pourrait se repreacutesenter unobjet comme une structure de donneacutees

Un objet est composeacute de proprieacuteteacutes (ce qui correspond agrave nos variables) et de meacutethodes (des fonctions) Pour creacuteerun objet on fait appel agrave son constructeur il sagit dune fonction qui a pour but de creacuteer et dinitialiser lobjet A la finde sa vie lobjet doit ecirctre deacutetruit cest le but du destructeur

Dans la vie courante on peut creacuteer des objets complexes agrave partir de briques de base il est possible de creacuteer denouveaux objets en se basant sur un ou plusieurs objets ce meacutecanisme est appeler heacuteritage (on parle dheacuteritagemultiple lorsquil met en jeu plusieurs objets parents) Lobjet ainsi obtenu heacuterite des proprieacuteteacutes et des meacutethodes deses parents tout en pouvant modifier leur comportement et creacuteer ses propres proprieacuteteacutes et meacutethodes

Lorsque lon souhaite creacuteer un patron pour de futures classes plutocirct que de creacuteer une classe de base qui ne serajamais instancieacutee il est possible de creacuteer une interface

Le dernier concept de POO qui va nous servir dans ce tutoriel est le polymorphisme Ceci permet agrave un objet (prenonspar exemple camion) de se comporter comme lun de ses parents (dans le cas du camion il peut ecirctre vu comme unveacutehicule au mecircme titre quune voiture) Ceci est aussi valable pour des classes impleacutementant la mecircme interface

Pour vous initier aux joies de la programmation orienteacutee objet en C je vous conseille le tutoriel de CGI POO en C

I-G - Notre premier programme

Un programme qui utilise GTK+ est un programme eacutecrit en C avant tout il contient donc le code de base de toutprogramme C

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 7 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

maincinclude ltstdlibhgt

int main (int argc char argv) return EXIT_SUCCESS

Pour pouvoir utiliser les fonctions de GTK+ il faut bien sucircr inclure le fichier den-tecircte correspondant

include ltgtkgtkhgt

La premiegravere chose agrave faire est dinitialiser la machinerie GTK+ gracircce agrave la fonction gtk_init

void gtk_init (int argc char argv)

Cette fonction reccediloit les arguments passeacutes en ligne de commande ceux qui sont speacutecifiques agrave GTK+ sont ensuiteretireacutes de la liste dougrave lutilisation des pointeurs

Ensuite il nous faut creacuteer tous les widgets dont nous avons besoin si neacutecessaire modifier leurs paramegravetres pardeacutefaut les connecter agrave des fonctions callback et ensuite demander leur affichage (tout ceci sera expliciteacute dans lasuite du tutoriel) Une fois la fenecirctre principale creacuteeacutee il suffit de lancer la boucle principale de GTK+

void gtk_main (void)

Cette fonction est une boucle sans fin (seule la fonction gtk_main_quit permet den sortir) qui se charge de geacuterer ledeacuteroulement de notre programme (affichage des widgets envoi de signaux)

Voici donc notre premier programme en CGTK+ qui ne fait rien

maincinclude ltstdlibhgtinclude ltgtkgtkhgt

int main (int argc char argv) Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application

Lancement de la boucle principale gtk_main() return EXIT_SUCCESS

En plus de ne rien faire notre programme ne peut ecirctre termineacute que de faccedilon brutale (Ctrl+C) puisque nous nappelonspas la fonction gtk_main_quit

I-H - Code source

chapitre1zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 8 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

II - Notre premiegravere fenecirctre

II-A - Aperccedilu

II-B - Creacuteation

La fenecirctre principale est repreacutesenteacutee par la classe GtkWindow

La creacuteation dune fenecirctre se fait simplement en appelant le constructeur de cette classe la fonction gtk_window_new

GtkWidget gtk_window_new (GtkWindowType type)

Le seul paramegravetre de cette fonction est le type de fenecirctre souhaiteacute Il ny a que deux possibiliteacutes

bull GTK_WINDOW_TOPLEVEL une fenecirctre classique (cest la base de notre application)

bull GTK_WINDOW_POPUP il sagit dune fenecirctre avec seulement lespace de travail (pas de bordure ni demenu systegraveme)

Cette fonction renvoie un pointeur sur une structure de type GtkWindow (transformer en GtkWidget gracircce aupolymorphisme) qui est lentiteacute qui va nous servir agrave manipuler notre fenecirctre

II-C - Affichage

Si vous essayez deacutecrire un code maintenant vous ne verrez rien pourquoi Tout simplement parce quil faut preacuteciseragrave GTK+ quil faut rendre notre fenecirctre visible gracircce agrave la fonction gtk_widget_show

void gtk_widget_show (GtkWidget widget)

Voici le code qui permet dafficher notre premiegravere fenecirctre

maincinclude ltstdlibhgtinclude ltgtkgtkhgt

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL)

Affichage de la fenetre principale gtk_widget_show (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 9 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Ceux qui se sont essayeacutes agrave la creacuteation dapplications graphiques avec lAPI Windows comprendront la simpliciteacutede ce code

II-D - Destruction

Dans lexemple preacuteceacutedent si vous avez essayeacute de terminer lapplication en fermant la fenecirctre (Alt+F4 ou en cliquantsur la petite croix) vous vous ecirctes peut-ecirctre aperccedilu que lapplication tournait encore en fond cest le mecircme problegravemeque pour le chapitre preacuteceacutedent on ne fait pas appel agrave gtk_main_quit Mais comment appeler cette fonction puisquequune fois gtk_main appeleacutee nous ne pouvons rien faire Cest lagrave quintervient le meacutecanisme des callback A chaqueeacuteveacutenement qui se produit la bibliothegraveque GObject produit un signal si nous souhaitons modifier le comportementpar deacutefaut du signal il suffit de connecter notre fonction callback agrave leacuteveacutenement souhaiteacute

define g_signal_connect(instance detailed_signal c_handler data)

Cette macro permet dintercepter leacuteveacutenement detailed_signal de lobjet instance gracircce agrave la fonction c_handler quidoit ecirctre du type GCallback

void (GCallback) (void)

Les fonctions callback peuvent bien sucircr recevoir des paramegravetres mais leur nature et leur nombre deacutependent ducontexte tout est geacutereacute par la bibliothegraveque GObject Le prototype le plus courant pour une fonction de rappel estle suivant

void callback (GtkWidget p_widget gpointer user_data)

Dont le premier paramegravetre est le widget qui a reccedilu le signal et le second correspond au paramegravetre data de la fonctiong_signal_connect qui nous permet de passer des informations aux fonctions callback Pour finir proprement notreapplication il suffit dintercepter le signal destroy de notre fenecirctre et dy assigner la fonction gtk_main_quit qui neprend pas dargument Voici donc notre premiegravere application fonctionnelle

maincinclude ltstdlibhgtinclude ltgtkgtkhgt

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (gtk_main_quit) NULL)

Affichage de la fenetre principale gtk_widget_show (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

Il est plus courant de creacuteer notre propre fonction de rappel pour quitter le programme ceci permet de libeacuterer lameacutemoire alloueacutee fermer les fichiers ouverts

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 10 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

maincinclude ltstdlibhgtinclude ltgtkgtkhgt

void cb_quit (GtkWidget gpointer)

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (cb_quit) NULL)

Affichage de la fenetre principale gtk_widget_show (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

void cb_quit (GtkWidget p_widget gpointer user_data) gtk_main_quit()

Parametres inutilises (void)p_widget (void)user_data

Le preacutefixe cb_ permet de diffeacuterencier les fonctions callback quil est preacutefeacuterable de regrouper dans un ou plusieursfichiers seacutepareacutes

A la fin de la fonction je transtype les paramegravetres inutiliseacutes pour eacuteviter que moncompilateur mindique des variables non utiliseacutees cest le problegraveme avec les fonctionscallback lAPI nous impose un prototype

II-E - Code source

chapitre2zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 11 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

III - Fermer notre fenecirctre gracircce aux boutons

III-A - Aperccedilu

III-B - Les boutons poussoir

Maintenant que notre programme se termine proprement il est plus convivial de proposer agrave lutilisateur un boutonpour quitter Pour creacuteer un bouton poussoir il existe plusieurs possibiliteacutes

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 premiegravere fonction creacutee un bouton qui peut servir pour contenir nimporte quel autre widget (label image) Si voussouhaitez creacuteer un bouton avec du texte dessus utilisez directement la seconde fonction qui prend en argument letexte agrave afficher Si vous souhaitez ajouter un raccourci clavier (accessible avec la touche Alt) la troisiegraveme fonctionpermet den speacutecifier un en faisant preacuteceacuteder une lettre (geacuteneacuteralement la premiegravere) dun underscore _ (si voussouhaitez afficher le caractegravere _ il faut en mettre deux) Enfin la derniegravere fonction permet dutiliser les Stock Itemsqui sont un ensemble deacuteleacutements preacutedeacutefinis par GTK+ pour les menus et barres doutils Le seul paramegravetre de cettefonction est le nom de leacuteleacutement et GTK+ se charge dafficher licocircne approprieacutee ainsi que le texte suivant la languechoisie et un raccourci

Cest bien sucircr cette derniegravere fonction que nous allons utiliser et ce le plus souvent possible Voici le code pour creacuteerun tel bouton

maincGtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_QUIT)

Pour obtenir tous les types de stocks items disponibles GtkStockItem

Bien sucircr comme pour la fenecirctre si lon veut voir quelque chose il faut demander agrave GTK+ dafficher notre widget

maincgtk_widget_show (p_button)

Mais pas seulement En effet il faut preacuteciser agrave GTK+ ougrave doit ecirctre afficheacute notre bouton Pour cela la classe GtkWindowest deacuteriveacutee de la classe GtkContainer qui est comme son nom le laisse penser un conteneur pour widget Pourajouter un widget il suffit de faire appel agrave la fonction gtk_container_add

void gtk_container_add (GtkContainer container GtkWidget widget)

Le premier paramegravetre de cette fonction est un GtkContainer or nous souhaitons passer notre fenecirctre qui est unGtkWidget pour ne pas avoir de problegravemes il faut utiliser le systegraveme de macro offert par GTK+ pour transtyper notreGtkWidget en GtkContainer (eh oui en C le polymorphisme a ses limites)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 12 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

maincgtk_container_add (GTK_CONTAINER (p_window) p_button)

Ce meacutecanisme de transtypage permet agrave GTK+ de veacuterifier que notre GtkWidget est bien compatible avec lutilisationque lon souhaite en faire En cas deacutechec GTK+ nous preacutevient en affichant un message dans la console

(gtk_boutonexe1044) Gtk-CRITICAL gtk_container_add assertion `GTK_IS_CONTAINER (container) failed

Pour finir il faut connecter notre bouton pour appeler notre fonction cb_quit lorsque lutilisateur clic dessus (ce quicorrespond agrave leacuteveacutenement clicked)

g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_quit) NULL)

Pour eacuteviter dappeler la fonction gtk_widget_show pour tous les widgets de notreapplication on peut se contenter dun seul appel agrave la fonction gtk_widget_show_all quipermet dafficher tous les widgets contenus dans celui passeacute agrave la fonction

maincinclude ltstdlibhgtinclude ltgtkgtkhgtinclude callbackh

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (cb_quit) NULL)

GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_QUIT) gtk_container_add (GTK_CONTAINER (p_window) p_button) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_quit) NULL)

Affichage de la fenetre principale gtk_widget_show_all (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

III-C - Code source

chapitre3zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 13 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IV - Comment afficher plusieurs widgets

IV-A - Aperccedilu

IV-B - Le problegraveme

Dans la partie preacuteceacutedente nous avons reacuteussi agrave afficher un bouton dans la fenecirctre de notre application Si vous avezessayeacute dajouter un second widget GTK+ agrave ducirc vous reacutepondre poliment

(gtk_boxexe492) Gtk-WARNING Attempting to add a widget with typeGtkButton to a GtkWindow but as a GtkBin subclass a GtkWindow can only containone widget at a time it already contains a widget of type GtkButton

Les plus anglophiles dentre vous auront compris que GTK+ naccepte pas lajout un second widget dans notre fenecirctretout simplement parce quil y en a deacutejagrave un et que la sous classe GtkBin (classe megravere de notre GtkWindow) ne peutcontenir quun seul widget

IV-C - La solutions

Pour contourner ce problegraveme il faut commencer par creacuteer un widget qui accepte den contenir plusieurs autrespour ensuite y ajouter tout ce dont nous avons besoin Pour linstant nous utiliserons quun seul widget (il existetrois classes qui permettent ceci) il sagit des GtkBox Il sagit de la meacutethode que jutilise le plus souvent Ce nestpeut-ecirctre pas la plus simple agrave maicirctriser mais elle extrecircmement souple et puissante Elle consiste agrave creacuteer une boicirctepuis agrave y ajouter les widgets les uns apregraves les autres (soit au deacutebut soit agrave la fin) Il existe deux classes heacuteritant deGtkBox les GtkVBox qui empilent les widgets dans le sens vertical et les GtkHBox qui font de mecircme mais dansle sens horizontal Les fonctions pour manipuler ces deux classes sont les mecircmes seule la fonction pour les creacuteerportent un nom diffeacuterent

GtkWidget gtk_vbox_new (gboolean homogeneous gint spacing)GtkWidget gtk_hbox_new (gboolean homogeneous gint spacing)

Le paramegravetre homogeneous permet de reacuteserver pour chaque widget une zone de taille identique (zone que le widgetnest pas obligeacute de remplir) et spacing permet dajouter une bordure en pixels (espacement autour de la GtkBox)Ensuite il suffit dajouter les diffeacuterents widgets gracircce aux fonctions

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)

Qui ajoutent reacuteciproquement le widget child au deacutebut et agrave la fin de box Le paramegravetre expand permet au widget davoirle plus de place possible (si le paramegravetre homogeneous vaut TRUE cette option a aucun effet) Si plusieurs widgetont ce paramegravetre agrave TRUE ils se partagent de faccedilon eacutegale lespace Loption fill permet au widget de remplir toutlespace qui lui ait reacuteserveacute

Pour reacuteellement comprendre linfluence de ces paramegravetres il faut faire des tests en modifiant un agrave un chaqueparamegravetre et observer les effets dun redimentionnement de la fenecirctre principale

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 14 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Le plus gecircnant avec cette meacutethode cest quil faut jongler entre les GtkHBox et les GtkVBox en les imbriquant pourobtenir le reacutesultat souhaiter nheacutesitez pas agrave utiliser une feuille et un crayon )

Pour en revenir agrave notre eacutediteur de texte nous allons preacuteparer notre application agrave contenir les futurs widgetsNous utilisons un GtkVBox pour lensemble des widgets (il sagit de la boicircte principale qui pourra contenir dautresGtkContainer selon nos besoins)

maincinclude ltstdlibhgtinclude ltgtkgtkhgtinclude callbackh

int main (int argc char argv) GtkWidget p_window = NULL GtkWidget p_main_box = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (cb_quit) NULL)

Creation du conteneur principal p_main_box = gtk_vbox_new (FALSE 0) gtk_container_add (GTK_CONTAINER (p_window) p_main_box)

Creation du bouton Quitter GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_QUIT) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_quit) NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_button FALSE FALSE 0)

Affichage de la fenetre principale gtk_widget_show_all (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

IV-D - Code source

chapitre4zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 15 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

V - Afficher le contenue dun fichier

V-A - Aperccedilu

Cliquez pour agrandir

V-B - Saisir du texte

Les choses seacuterieuses vont commencer il sagit de mettre en place le widget qui va nous permettre dafficher etdeacutediter du texte Il sagit de la classe GtkTextView Gracircce agrave GTK+ la mise en place est toujours aussi simple

mainc GtkWidget p_text_view = NULL Creation de la zone de texte p_text_view = gtk_text_view_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_text_view TRUE TRUE 0)

Comme il sagit de la partie centrale de notre application nous demandons agrave ce quelle prenne le plus de placepossible (gracircce agrave la fonction gtk_box_pack_start)

Puisque nous voulons afficher les boutons en dessous de la zone de texte il faut ajouter ce morceau de code avantcelui creacuteant le bouton

V-C - Ouvrir un fichier

Maintenant nous avons une belle zone de texte il faut la remplir avec le contenu dun fichier Pour ce faire nousallons commencer par ajouter un bouton ouvrir

mainc Creation du bouton Ouvrir GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_OPEN) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_open) p_text_view) gtk_box_pack_start (GTK_BOX (p_main_box) p_button FALSE FALSE 0)

Si vous exeacutecutez le programme maintenant (3) vous remarquerez que les boutons sont ajouteacutes les uns en dessousdes autres ce qui diminue la zone de saisie (avec deux boutons ce nest pas gecircnant mais au bout dune dizaineccedila risque decirctre probleacutematique) Pour pallier ce problegraveme nous allons utiliser un nouveau style de GtkBox lesGtkButtonBox qui sont preacutevus pour contenir des boutons (ccedila tombe plutocirct bien D) Donc pour eacuteviter de diminuerla zone de saisie et comme nous avons de la place en largueur nous allons utiliser un GtkHButtonBox qui va ecirctreinclus dans la p_main_box Voici les modifications agrave effectuer

mainc GtkWidget p_button_box = NULL Creation du conteneur pour les boutons p_button_box = gtk_hbutton_box_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_button_box FALSE FALSE 0)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 16 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc gtk_box_pack_start (GTK_BOX (p_button_box) p_button FALSE FALSE 0) gtk_box_pack_start (GTK_BOX (p_button_box) p_button FALSE FALSE 0)

Maintenant il nous reste plus quagrave creacuteer la fonction cb_open dans le fichier callbackc pour linstant nous nouscontenterons douvrir toujours le mecircme fichier nous verrons plus tard comment laisser le choix agrave lutilisateur

callbackcdefine DEFAULT_FILE mainc

void cb_open (GtkWidget p_widget gpointer user_data) open_file (DEFAULT_FILE GTK_TEXT_VIEW (user_data))

Parametre inutilise (void)p_widget

Vous aurez compris que lon va deacuteleacuteguer tout le travail agrave la fonction open_file qui devra ouvrir le fichier dont le nomest passeacute en premier paramegravetre pour lafficher dans le GktTextView

Jai fait ce choix pour deux raisons le code dune fonction callback peut ecirctre tregraves conseacutequent (surtout si lon souhaitequelle affiche une boicircte de dialogue) et aussi parce que cb_open nest peut ecirctre pas la seule fonction agrave copierun fichier dans un GtkTextView (par exemple lors de la creacuteation dun nouveau fichier lon peut vouloir copier unsquelette de fichier)

Pour copier notre fichier plutocirct que dutiliser la fonction fgets nous allons nous servir de la glib (4) qui proposela fonction

gboolean g_file_get_contents (const gchar filename gchar contents gsize length GError error)

Qui nous renvoit le contenu du fichier nommeacute filename dans le tampon contents Il est possible de reacutecupeacuterer lenombre de caractegraveres copieacutes et retourne TRUE en cas de succegraves sinon FALSE et dans ce cas une structure de typeGError est creacutee pour en savoir plus sur le type derreur rencontreacute

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView else print_warning (Impossible douvrir le fichier sn file_name)

Je pense quun certain nombre dexplications simpose (surtout si je vais trop vite nheacutesitez pas agrave marrecircter )

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 17 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

bull g_return_if_fail est une macro qui peut ecirctre compareacutee agrave assert sauf quelle se contente de sortir de la fonctionsi lexpression passeacutee en paramegravetre est fausse Cest une meacutethode pratique pour veacuterifier la validiteacute desparamegravetres (si la fonction doit retourne une valeur utiliseacute plutocirct g_return_val_if_fail qui prend un secondparamegravetre la valeur agrave retourner)

bull Ensuite on essaie de reacutecupeacuterer le contenu de notre fichier

bull Si cela eacutechoue nous le signalons agrave lutilisateur agrave laide de la fonction print_warning

bull Le type gchar est une redeacutefinition du type char par la glib (il en va de mecircme pour tous les autres types du C)privileacutegiez ces types lorsque vous utilisez des fonctions de cette bibliothegraveques

Mais quest-ce donc cette fonction print_warning Cest une fonction que nous allons creacuteer semblable agrave printf quisignalera agrave lutilisateur quune erreur non critique est survenue Comme nous navons pas encore abordeacute les boicirctesde dialogue pour afficher un message il sagira pour linstant dune simple redeacutefinition de printf Pendant que noussommes dans laffichage des messages nous allons aussi creacuteer deux fonctions print_info et print_error qui vontrespectivement afficher un message dinformation et un message derreur critique (ce qui entraicircne la terminaison duprogramme) tout ceci dans un nouveau fichier errorc

errorhifndef H_ERRORdefine H_ERROR

void print_info (char )void print_warning (char )void print_error (char )

endif not H_ERROR

errorcinclude ltstdarghgtinclude ltstdiohgtinclude ltstdlibhgtinclude errorh

void print_info (char format ) va_list va

va_start (va format) printf (Information ) vprintf (format va) printf (n)

void print_warning (char format ) va_list va

va_start (va format) fprintf (stderr Erreur ) vfprintf (stderr format va) fprintf (stderr n)

void print_error (char format ) va_list va

va_start (va format) fprintf (stderr Erreur fatale ) vfprintf (stderr format va) fprintf (stderr n) exit (EXIT_FAILURE)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 18 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

Pour en finir avec louverture dun fichier il nous reste agrave copier contents dans le GtkTextView En fait le GtkTextViewne gegravere que la forme pour modifier le contenu il faut passer par les GtkTextBuffer Commenccedilons donc par reacutecupeacutererce fameux GtkTextBuffer

callbackc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (p_text_view)

Et pour finir on utilise la fonction

void gtk_text_buffer_insert (GtkTextBuffer buffer GtkTextIter iter const gchar text gint len)

Reacutecapitulons buffer est le GtkTextBuffer que lon vient de reacutecupeacuterer text cest le texte agrave afficher et len la taille dece dernier (ou -1 sil sagit dune chaicircne de caractegraveres au sens du langage C)

Mais quest-ce donc ce GtkTextIter On peut voir cela comme un curseur virtuel qui indique la position agrave laquelleeffectuer linsertion de texte dans le GtkTextBuffer (5) Allons voir ce que la documentation peut nous apprendreagrave leur sujet (6)

typedef struct GtkTextIter is an opaque datatype ignore all these fields Initialize the iter with gtk_text_buffer_get_iter_ functions GtkTextIter

Voilagrave on a notre solution suffit de rechercher les fonctions commenccedilant par gtk_text_buffer_get_iter_ voici la liste

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)

La fonction gtk_text_buffer_get_iter_at_line fait parfaitement laffaire

callbackc GtkTextIter iter

gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1)

Cependant si vous ne voulez pas avoir de problegravemes avec le codage des caractegraveres il vaut mieux convertir le codagelocal vers utf8 Voici le reacutesultat final

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 19 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gchar utf8 = NULL GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_text_buffer_insert (p_text_buffer ampiter utf8 -1) g_free (utf8) utf8 = NULL

V-D - La petite touche finale

Pour finir cette laborieuse partie sur une petite touche estheacutetique nous allons demander agrave GTK+ de nous lancerlapplication en plein eacutecran Pour se faire il suffit dajouter lors de la creacuteation de la fenecirctre principale

maincgtk_window_maximize (GTK_WINDOW (p_window))

On peut mecircme se permettre une pointe dexcentriciteacute en modifiant le titre de notre fenecirctre

maincgtk_window_set_title (GTK_WINDOW (p_window) Editeur de texte en GTK+)

V-E - Code source

chapitre5zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 20 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VI - Choisir un fichier

VI-A - Aperccedilu

Cliquez pour agrandir

VI-B - Utilisation dun GtkFileChooserFile

Jusquagrave preacutesent lutilisateur navait pas le choix quant au fichier agrave ouvrir heureusement GTK+ vient agrave notre aide gracircceau widget GtkFileChooserFile qui est tout simplement une boicircte de dialogue qui propose agrave lutilisateur de seacutelectionnerun fichier dans son arborescence disque

Commenccedilons par creacuteer notre boicircte de dialogue dans la fonction cb_open

callbackcvoid cb_open (GtkWidget p_widget gpointer user_data) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Ouvrir un fichier NULL GTK_FILE_CHOOSER_ACTION_OPEN GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_OPEN GTK_RESPONSE_ACCEPT NULL)

Cette fonction neacutecessite le titre de la boicircte de dialogue une fenecirctre parente le type daction (ici on souhaite ouvrir unfichier GTK+ autorisera lutilisateur agrave seacutelectionner uniquement les fichiers existants) Pour finir il sagit dun couple devaleurs GTK_STOCK_ITEMGTK_STOCK_RESPONSE qui permet de creacuteer un bouton utilisant le stock ID speacutecifieacuteet lorsque celui-ci est cliqueacute la fonction servant agrave lancer la boicircte de dialogue retournera le reacuteponse ID correspondantIl existe une seacuterie de valeurs deacutefinies par GTK+ quil est conseilleacute dutiliser

typedef enum GTK returns this if a response widget has no response_id or if the dialog gets programmatically hidden or destroyed GTK_RESPONSE_NONE = -1

GTK wont return these unless you pass them in as the response for an action widget They are for your convenience GTK_RESPONSE_REJECT = -2 GTK_RESPONSE_ACCEPT = -3

If the dialog is deleted GTK_RESPONSE_DELETE_EVENT = -4

These are returned from GTK dialogs and you can also use them yourself if you like GTK_RESPONSE_OK = -5 GTK_RESPONSE_CANCEL = -6 GTK_RESPONSE_CLOSE = -7 GTK_RESPONSE_YES = -8

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 21 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GTK_RESPONSE_NO = -9 GTK_RESPONSE_APPLY = -10 GTK_RESPONSE_HELP = -11 GtkResponseType

Nous indiquons la fin des couples stock idreacuteponse id avec la valeur NULL

Une fois la boicircte de dialogue creacuteee on demande agrave GTK+ de lafficher gracircce agrave la fonction gtk_dialog_run puis onreacutecupegravere sa valeur de retour qui correspond au bouton cliqueacute par lutilisateur

callbackc if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

Ici ce qui nous inteacuteresse cest lorsque que lutilisateur clique sur le bouton ouvrir (donc gtk_dialog_run renvoieGTK_RESPONSE_ACCEPT) dans ce cas il nous suffit de reacutecupeacuterer le nom du fichier seacutelectionneacute puis de louvrir

callbackc gchar file_name = NULL

file_name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) open_file (file_name GTK_TEXT_VIEW (user_data)) g_free (file_name) file_name = NULL

Pour finir dans tous les cas on noublie pas de deacutetruire la boicircte de dialogue

callbackc gtk_widget_destroy (p_dialog)

Et voilagrave le travail lutilisateur peut ouvrir le fichier quil souhaite

VI-C - Code source

chapitre6zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 22 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VII - Interlude

Avant daller plus loin dans lameacutelioration de linterface de notre eacutediteur il est neacutecessaire de modifier sonfonctionnement interne (ne vous inquieacutetez je nai pas dit chambouler) en effet souvenez-vous dans lintroduction jaieacutevoqueacute la possibiliteacutes douvrir plusieurs documents gracircce agrave un systegraveme donglets Pour cela il faut sauvegarder lesproprieacuteteacutes de chaque document ouvert Pris agrave temps ce genre de modification nest pas trop lourde mais si nousattendons cela risque de devenir un vrai casse tecircte

Pour cela nous allons utiliser une structure de donneacutee pour chaque document ouvert qui devra garder en meacutemoirele chemin complet du fichier (ou NULL si le document nest pas encore sauvegarder) sil agrave eacutetait modifier depuis laderniegravere sauvegarde et le GtkTextView qui sert agrave son affichage Voici donc la structure qui va nous servir

documenthtypedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

Sachant que nous serons ameneacute agrave stocker plusieurs occurrences de cette structure il serait bon de reacutefleacutechir degravesmaintenant agrave la structure de donneacutee agrave utiliser pour les stocker La premiegravere ideacutee qui vient agrave lesprit est un tableaualloueacute dynamiquement cependant lutilisateur peut souhaiter fermer un document qui se trouve au milieu on estalors obligeacute de deacutecaler toutes les cellules en amont Dans ce cas il parait naturel dutiliser une liste chaicircneacutee Parchance la glib propose une bibliothegraveque de gestion des listes chaicircneacutees cela nous fera gagner du temps le momentvenu Pour linstant on se contente de creacuteer une structure de donneacutees qui contiendra tous les documents ouverts(stockeacutee dans une GList) et un pointeur sur le document actif (actuellement comme nous navons quun documentouvert en mecircme temps on manipulera uniquement ce pointeur)

documenthtypedef struct GList tous document_t actif docs_t

Maintenant se pose le problegraveme de savoir comment transmettre cette structure On pourrait se servir du paramegravetreuser_data preacutesent dans toutes les fonctions callback mais certaines fonctions utilise deacutejagrave ce paramegravetre (la fonctioncb_open par exemple) il faudrait creacuteer un champs suppleacutementaire dans notre structure documents_s Une solutionplus simple est de creacuteer une variable globale agrave lensemble du programme Ceux qui passe reacuteguliegraverement sur le forumC savent que cest fortement deacuteconseilleacute mais ici nous nous trouvons dans lune des rares exceptions agrave la regravegle Detoute faccedilon cela revient au mecircme que de passer ladresse de notre structure agrave toutes les fonctions callback Nousdeacutefinissons donc un nouveau fichier den-tecircte

documenthifndef H_DOCUMENTdefine H_DOCUMENT

include ltgtkgtkhgt

typedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 23 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

documenthtypedef struct GList tous document_t actif docs_t

extern docs_t docs

endif not H_DOCUMENT

Et dans le fichier mainc

maincinclude documenth

docs_t docs = NULL NULL

Pour linstant la seule fonction qui modifie leacutetat dun document est la fonction open_file il faut donc inclure documenthdans callbackc et modifier leacutegegraverement la fonction pour enregistrer le document ouvert

callbackc if (g_file_get_contents (file_name ampcontents NULL NULL)) Pour linstant il faut allouer la memoire par la suite on modifira simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = g_strdup (file_name) Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = p_text_view Le document vient detre ouvert il nest donc pas modifie docsactif-gtsauve = TRUE

Ne soyez pas choqueacute si je ne teste pas le retour de la fonction g_malloc pour veacuterifier quilnest pas NULL En effet cette derniegravere met fin agrave lapplication si lallocation eacutechoue

VII-A - Code source

chapitre7zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 24 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VIII - Sauvegarder les modification

VIII-A - Aperccedilu

Cliquez pour agrandir

VIII-B - Enregistrer

Avant de pouvoir sauvegarder un document il faut quil soit modifieacute Comment savoir que le contenu du fichier a eacuteteacutemodifier Gracircce au signal changed du GtkTextBuffer que nous interceptons gracircce agrave la fonction cb_modifie

mainc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (p_text_view)) g_signal_connect (G_OBJECT (p_text_buffer) changed G_CALLBACK (cb_modifie) NULL)

Cette derniegravere modifie simplement le champ sauve du document

callbackcvoid cb_modifie (GtkWidget p_widget gpointer user_data) if (docsactif) docsactif-gtsauve = FALSE

Pour la sauvegarde il faut distinguer deux cas soit il sagit de la premiegravere sauvegarde du fichier il faut alors demanderle nom du fichier agrave lutilisateur (cela ressemble fortement agrave louverture dun fichier) soit le fichier est deacutejagrave preacutesent surle disque il suffit de remplacer son contenu par celui du GtkTextViewer Nous avons convenu quun fichier qui neacutetaitpas encore enregistreacute avait sa proprieacuteteacute chemin agrave NULL

Bien sucircr cela na lieu que si un fichier est ouvert et quil a eacuteteacute modifieacute depuis sa derniegravere sauvegarde

callbackcvoid cb_save (GtkWidget p_widget gpointer user_data) if (docsactif) if (docsactif-gtsauve) Le fichier na pas encore ete enregistre if (docsactif-gtchemin) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Sauvegarder le fichier NULL GTK_FILE_CHOOSER_ACTION_SAVE GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_SAVE GTK_RESPONSE_ACCEPT NULL) if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 25 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc docsactif-gtchemin = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) gtk_widget_destroy (p_dialog) Soit le fichier a deja ete enregistre soit lutilisateur vient de nous fournir son nouvel enplacement on peut donc lenregistrer if (docsactif-gtchemin) else print_warning (Aucun document ouvert)

Il nous reste plus quagrave reacutecupeacuterer le contenu du GtkTextViewer et le copier dans le fichier chemin sans oublier dereconvertir le texte dans le codage local

callbackc FILE fichier = NULL

fichier = fopen (docsactif-gtchemin w) if (fichier) gchar contents = NULL gchar locale = NULL GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) contents = gtk_text_buffer_get_text (p_text_buffer ampstart ampend FALSE) locale = g_locale_from_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL fprintf (fichier s locale) g_free (locale) locale = NULL fclose (fichier) fichier = NULL docsactif-gtsauve = TRUE else print_warning (Impossible de sauvegarder le fichier s docsactif-gtchemin)

Le dernier paramegravetre de la fonction gtk_text_buffer_get_text est mis agrave FALSE car nous ne voulons pas enregistrerles caractegraveres invisibles preacutesent dans le GtkTextBuffer Ces caractegraveres servent agrave mettre en forme le texte (taillecouleur) nous pourrions creacuteer un nouveau format de fichier pour enregistrer la mise en forme

VIII-C - Enregistrer sous

Pour enregistrer notre document sous un autre nom il suffit de faire croire agrave cb_save que le document na pas encoreeacutetait enregistreacute tout simplement en changeant chemin agrave NULL et sauve agrave FALSE

callbackcvoid cb_saveas (GtkWidget p_widget gpointer user_data)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 26 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (docsactif) document_t tmp = docsactif

docsactif-gtchemin = NULL docsactif-gtsauve = FALSE cb_save (p_widget user_data) if (docsactif-gtsauve) (docsactif) = tmp else print_warning (Aucun document ouvert)

Il ne faut pas oublier que lutilisateur peut annuler lenregistrement de ce fait nous sauvegardons leacutetat du documentet si la sauvegarde na pas eu lieu on le restaure

VIII-D - Code source

chapitre8zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 27 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IX - Creacuteer un nouveau document

IX-A - Aperccedilu

Cliquez pour agrandir

IX-B - Nouveau fichier

Maintenant que lutilisateur peut ouvrir et fermer un fichier il est inteacuteressant de lui donner la possibiliteacute den creacuteerun nouveau Je ne reviens pas sur la creacuteation du bouton (ccedila devrait deacutejagrave ecirctre fait D) passons directement agrave lafonction cb_new

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) Pour linstant il faut allouer la memoire par la suite on modifiera simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = NULL Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = GTK_TEXT_VIEW (user_data) Le document vient detre creer il nest donc pas modifie docsactif-gtsauve = TRUE gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Je ne sais pas vous mais pour ma part jai fait un copiercoller de la fonction open_file Et oui ouvrir un document peutse reacutesumer agrave creacuteer un document vide puis remplir le GtkTextView avec le fichier souhaiteacute On peut donc simplifiernotre fonction open_file ainsi

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

cb_new (NULL p_text_view) gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE) p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1) Nous sommes obliges de remetre sauve a TRUE car linsertion du contenu du fichier dans le GtkTextView a appele cb_modfie docsactif-gtsauve = TRUE else print_warning (Impossible douvrir le fichier sn file_name)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 28 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc

Cest beau la factorisation du code Par contre nous sommes obligeacutes de remettre sauve agrave TRUE car nous avonsmodifieacute le GtkTextBuffer

IX-C - Code source

chapitre9zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 29 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

X - Fermer

X-A - Aperccedilu

Cliquez pour agrandir

X-B - Fermer un fichier

Maintenant que nous allouons de la meacutemoire il faut la libeacuterer agrave un endroit Logiquement cela va ecirctre fait agrave la fermeturedu document en guise dexercice je vous laisse creacuteer le bouton dans notre boicircte agrave bouton

Allez je vous aide le stock id correspondant est GTK_STOCK_CLOSE

Voilagrave maintenant si tout cest bien passeacute vous devriez ecirctre arriveacute dans le fichier callbackc avec quelque choseressemblant agrave

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data)

Lorsque lon ferme un document il faut vider le GtkTextView (avec les onglets on se contentera de le supprimer)pour cela il faut reacutecupeacuterer le deacutebut et la fin du GtkTextBuffer et demander agrave GTK+ de supprimer tout ce qui ce trouveentre les deux iteacuterateurs

callbackc Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) gtk_text_buffer_delete (p_text_buffer ampstart ampend) else print_warning (Aucun document ouvert)

Bien sucircr il ne faut pas oublier de libeacuterer la meacutemoire

callbackc g_free (docsactif-gtchemin) docsactif-gtchemin = NULL docsactif-gtp_text_view = NULL g_free (docsactif) docsactif = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 30 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour symboliser la fermeture dun document nous deacutesactivons le GtkTextView lors de la fermeture (ne pas oublierde le faire aussi dans mainc)

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) FALSE)

Et nous le reacuteactivons lors de louverture si celle si reacuteussie

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Lorsque lutilisateur quitte lapplication il faut bien sucircr fermer le document sil y en a un ouvert

void cb_quit (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data) gtk_main_quit()

Et aussi lorsquil creacuteeacute un nouveau document (et par conseacutequent lorsquil ouvre un fichier puisque lon fait appel agravecb_new)

void cb_new (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data)

X-C - Enregistrer avant de fermer

Si le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde geacuteneacuteralement le programme le signale agrave lutilisateur etlui propose de sauvegarder ou dannuler la fermeture Pour se faire nous devons modifier la fonction cb_close avantde fermer le document nous allons afficher une boicircte de dialogue

Pour creacuteer une boicircte de dialogue simplement il existe la classe GtkDialog et comme nous avons besoin de boutons(pour que lutilisateur fasse son choix) nous allons creacuteer notre boicircte avec la fonction

GtkWidget gtk_dialog_new_with_buttons (const gchar title GtkWindow parent GtkDialogFlags flags const gchar first_button_text )

Nous retrouvons les mecircmes options que pour le GtkFileChooserDialog mis agrave part option du type GtkDialogFlags

typedef enum GTK_DIALOG_MODAL = 1 ltlt 0 appel gtk_window_set_modal (win TRUE) GTK_DIALOG_DESTROY_WITH_PARENT = 1 ltlt 1 appel gtk_window_set_destroy_with_parent () GTK_DIALOG_NO_SEPARATOR = 1 ltlt 2 Pas de barre de separation au dessus des boutons GtkDialogFlags

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 31 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Nous nous contenterons de rendre notre fenecirctre modale (7)

Pour avoir accegraves agrave notre fenecirctre principale nous ajoutons un champs p_main_window agrave notre structure globaledocs_t que nous initialisons dans la fonction main

mainc docsp_main_window = GTK_WINDOW (p_window)

Il nous reste plus qua creacuteer notre boicircte de dialogue avec trois boutons Oui Non Annuler

callbackc if (docsactif-gtsauve) GtkWidget p_dialog = NULL

p_dialog = gtk_dialog_new_with_buttons (Sauvegarder docsp_main_window GTK_DIALOG_MODAL GTK_STOCK_YES GTK_RESPONSE_YES GTK_STOCK_NO GTK_RESPONSE_NO GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL NULL)

Nous obtenons donc une structure de type GtkDialog

typedef struct GtkWidget vbox GtkWidget action_area GtkDialog

Nous remarquons que cette structure contient deux membres qui permettent dacceacuteder agrave une GtkBox ougrave nous allonsajouter le contenu de la fenecirctre et agrave la partie contenant les boutons

Ensuite la construction de la fenecirctre est identique agrave celle de la fenecirctre principale ici nous nous contenterons dajouterun GtkLabel

callbackc GtkWidget p_label = NULL p_label = gtk_label_new (Voulez-vous sauvegarder les modifications ) gtk_box_pack_start (GTK_BOX (GTK_DIALOG (p_dialog)-gtvbox) p_label TRUE TRUE 0)

Une fois notre fenecirctre precircte il suffit de faire appel agrave la fonction gtk_dialog_run qui va afficher notre GtkDialog et nousretourner le reacuteponse id correspondant au bouton cliqueacute par lutilisateur

callbackc switch (gtk_dialog_run (GTK_DIALOG (p_dialog))) case GTK_RESPONSE_YES cb_save (p_widget user_data) break case GTK_RESPONSE_NO break case GTK_RESPONSE_CANCEL gtk_widget_destroy (p_dialog) return break

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 32 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc gtk_widget_destroy (p_dialog)

Si lutilisateur clique sur non on ne fait rien (le document sera simplement fermeacute) sur oui on enregistre avant defermer et pour finir sil annule on quitte la fonction

X-D - Code source

chapitre10zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 33 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XI - Les barres de deacutefilement

XI-A - Aperccedilu

Cliquez pour agrandir

XI-B - Ajouter des barres de deacutefilement

Apregraves le dernier chapitre quelque peu laborieux voici une partie plus simple mais qui va rendre notre applicationplus pratique En effet si vous avez essayeacute douvrir un fichier de grande taille vous avez pu remarquer que pourpouvoir lire la fin du fichier il fallait utiliser les touches du clavier pas tregraves convivial

Pour rendre la navigation plus aiseacutee on utilise des barres de deacutefilement

mainc GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_scrolled_window TRUE TRUE 0)

Creation de la zone de texte gtk_container_add (GTK_CONTAINER (p_scrolled_window) p_text_view)

Le constructeur de notre GtkScrolledWindow prend en argument deux GtkAdjustment qui permettent de deacutefinirdiffeacuterentes proprieacuteteacutes de la barre de deacutefilement (taille dune page la position de deacutepart) nous laissons GTK+ faireen passant NULL

Cest un bon deacutebut mais estheacutetiquement on peut faire mieux mecircme sil nest pas utile davoir une barre de deacutefilementelle est quand mecircme afficheacutee On peut demander agrave GTK+ de les afficher que si cela est neacutecessaire

mainc gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC)

En fait nous avons de la chance car la classe GtkTextView fait partie des widget qui supporte de faccedilon native les barresde deacutefilement Comment le savoir Ce genre de widget possegravede une ou deux proprieacuteteacutes de type GtkAdjustment (unepour la barre verticale lautre pour la barre horizontale) Actuellement seulement trois classes en sont capables lesGtkTextView les GtkTreeView et les GtkLayout

Comment faire pour les autres widgets Il faut passer par une classe adaptateur GtkViewport afin de creacuteer lesGtkAdjustment

XI-C - Code source

chapitre11zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 34 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XII - Les menus

XII-A - Aperccedilu

Cliquez pour agrandir

XII-B - Creacuteation du menu

Pour simplifier nous avons utiliseacute des boutons pour permettre agrave lutilisateur de creacuteer un document ouvrir un fichierMais il est plus courant dutiliser un menu pour afficher ces options GTK+ propose trois maniegraveres de creacuteer un menu

bull GtkItemFactory cette meacutethode est obsolegravete depuis la version 24 de GTK+

bull GtkUIManager cest ce quon appel une usine agrave gaz pour en savoir plus vous pouvez vous reporter aututoriel Utilisation de GtkUIManager

bull GtkMenu cest ce widget que nous allons eacutetudier il permet de creacuteer un menu manuellement (agrave lopposeacute deGtkUIManager)

Un menu selon GTK+ est composeacute de plusieurs eacuteleacutements

bull GtkMenuBar la barre de menu elle-mecircme

bull GtkMenu la partie deacuteroulante qui contient les diffeacuterents eacuteleacutements

bull GtkMenuItem cest sur ce widget que lutilisateur clique pour lancer une action

Pour commencer faisons linventaire de ce que nous avons besoin

bull Un GtkMenuBar qui sert de base au menu

bull Un GtkMenu pour commencer nous nous aurons dun menu Fichier

bull Six GtkMenuItem pour remplacer nos six boutons

Commenccedilons par la creacuteation du menu nous mettons ce code dans un nouveau fichier dont seul la fonction menu_newsera accessible

menucGtkMenuBar menu_new (gpointer user_data) GtkWidget p_menu_bar = NULL

p_menu_bar = gtk_menu_bar_new () return GTK_MENU_BAR (p_menu_bar)

Le paramegravetre user_data nous servira lors de la connexion des callbacks (nous en avons besoin pour les fonctionscb_new et cb_open)

Ensuite nous allons creacuteer notre sous menu Fichier

menuc Menu Fichier

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 35 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

menuc GtkWidget p_menu = NULL GtkWidget p_menu_item = NULL

p_menu = gtk_menu_new () p_menu_item = gtk_menu_item_new_with_mnemonic (_Fichier) gtk_menu_item_set_submenu (GTK_MENU_ITEM (p_menu_item) p_menu) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu_bar) p_menu_item) return GTK_MENU_BAR (p_menu_bar)

Un sous menu est en fait un GtkMenuItem auquel on assigne un GtkMenu Il faut bien sucircr terminer la creacuteation dusous-menu en lajoutant agrave la barre de menu

Pour finir nous creacuteons les eacuteleacutements du menu les GtkItemMenu Il existe plusieurs types deacuteleacutements (comparableaux diffeacuterents types de bouton) pour commencer nous nutiliserons que le type de base Comme cette opeacuteration estreacutepeacutetitive nous allons creacuteer une fonction pour le faire

menucstatic void menu_item_new (GtkMenu p_menu const gchar title GCallback callback gpointer user_data) GtkWidget p_menu_item = NULL

p_menu_item = gtk_menu_item_new_with_mnemonic (title) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu) p_menu_item) g_signal_connect (G_OBJECT (p_menu_item) activate callback user_data)

Pour permettre agrave lutilisateur dacceacuteder aux diffeacuterents eacuteleacutements du menu agrave laide de la touche ltAltgt nous utilisonsdes mneacutemoniques par exemple pour quitter leacutediteur il suffit de faite Alt+F puis Q Et voici le code pour creacuteer nossix eacuteleacutements du menu

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau G_CALLBACK (cb_new) user_data) menu_item_new (GTK_MENU (p_menu) _Ouvrir G_CALLBACK (cb_open) user_data) menu_item_new (GTK_MENU (p_menu) _Enregistrer G_CALLBACK (cb_save) user_data) menu_item_new (GTK_MENU (p_menu) Enregistrer _sous G_CALLBACK (cb_saveas) user_data) menu_item_new (GTK_MENU (p_menu) _Fermer G_CALLBACK (cb_close) user_data) menu_item_new (GTK_MENU (p_menu) _Quitter G_CALLBACK (cb_quit) user_data)

Voilagrave notre menu est creacuteeacute il nous reste plus quagrave linteacutegrer agrave notre fenecirctre

mainc gtk_box_pack_start (GTK_BOX (p_main_box) GTK_WIDGET (menu_new (p_text_view)) FALSE FALSE 0)

Le problegraveme cest que nous avons besoin de passer le GtkTextView lors de la creacuteation du menu (qui est utiliseacute par lesfonctions cb_new et cb_open) or celui-ci est creacuteeacute apregraves le menu (puisque nous creacuteons les widgets dans lordre ougrave ilfaut les inteacutegrer agrave linterface (8) ) nous devons creacuteer le GtkTextView (seul lappel agrave gtk_text_view_new est deacuteplaceacute)

XII-C - Code source

chapitre12zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 36 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIII - Les barres doutils

XIII-A - Aperccedilu

Cliquez pour agrandir

XIII-B - Creacuteation dune barre doutils

La creacuteation dune barre doutils ressemble fort agrave celle dun menu en plus simple puisquil ny a pas de sous menu on creacutee notre barre doutils (gtk_toolbar_new) puis les eacuteleacutements de la barre pour cela on utilise des boutons(gtk_tool_button_new_from_stock) que lon inseacutere dans la barre (gtk_toolbar_insert) Pas conseacutequent notre fichierbarreoutilsc ressemble agrave menuc

barreoutilscinclude ltgtkgtkhgtinclude callbackhinclude barreoutilsh

static void toolbar_item_new (GtkToolbar const gchar GCallback gpointer)

GtkToolbar toolbar_new (gpointer user_data) GtkWidget p_toolbar = NULL

p_toolbar = gtk_toolbar_new () toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_NEW G_CALLBACK (cb_new) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_OPEN G_CALLBACK (cb_open) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE G_CALLBACK (cb_save) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE_AS G_CALLBACK (cb_saveas) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_CLOSE G_CALLBACK (cb_close) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_QUIT G_CALLBACK (cb_quit) user_data) return GTK_TOOLBAR (p_toolbar)

static void toolbar_item_new (GtkToolbar p_toolbar const gchar stock_id GCallback callback gpointer user_data) GtkToolItem p_tool_item = NULL

p_tool_item = gtk_tool_button_new_from_stock (stock_id) g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data) gtk_toolbar_insert (p_toolbar p_tool_item -1)

Le code nest pas complet car lorsque jexeacutecute le programme GTK+ affiche en plus des icocircnes le texte sous lesboutons Pour modifier cela il suffit dajouter une ligne de code

barreoutilsc gtk_toolbar_set_style (GTK_TOOLBAR (p_toolbar) GTK_TOOLBAR_ICONS)

Pourquoi gtk_tool_button_new_from_stock retourne un GtkToolItem et non un GtkWidgetcomme nous avons eacuteteacute habitueacute jusquagrave preacutesent Il sagit dune bizarrerie de GTK+ dontje ne connais pas la raison

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 37 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour anticiper un changement dinterface (dans GTK+ 30 peut ecirctre ) nous aurions pueacutecrire

Gtkwidget p_tool_item = NULL

p_tool_item = GTK_WIDGET (gtk_tool_button_new_from_stock (stock_id))g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data)gtk_toolbar_insert (p_toolbar GTK_TOOL_ITEM (p_tool_item) -1)

XIII-C - Code source

chapitre13zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 38 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIV - Les racourcis clavier

XIV-A - Aperccedilu

Cliquez pour agrandir

XIV-B - Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mneacutemoniques ces derniers permettent dacceacuteder agrave un eacuteleacutementseacutequentiellement alors que les raccourcis appellent une fonction si lutilisateur appuie simultaneacutement sur une ouplusieurs touches (geacuteneacuteralement de la forme ltModificateurgtTouche ougrave Modificateur repreacutesente les touches ShiftAlt et Control) Ce raccourci peut ecirctre attacheacute agrave un eacuteleacutement du menu mais ceci nest pas obligatoire

Les raccourcis sont regroupeacutes en groupe dans un GtkAccelGroup quil faut commencer par creacuteer

raccourciscinclude ltgtkgtkhgtinclude callbackhinclude raccourcish

GtkAccelGroup accel_group_new (gpointer user_data) GtkAccelGroup p_accel_group = NULL

p_accel_group = gtk_accel_group_new () return p_accel_group

Vous commencez agrave avoir lhabitude de cette organisation nous allons donc creacuteer une fonction qui va se chargerdajouter un raccourci au groupe

raccourciscstatic void accelerator_new (GtkAccelGroup p_accel_group const gchar accelerator const gchar accel_path GCallback callback gpointer user_data) guint key GdkModifierType mods GClosure closure = NULL

gtk_accelerator_parse (accelerator ampkey ampmods) closure = g_cclosure_new (callback user_data NULL) gtk_accel_group_connect (p_accel_group key mods GTK_ACCEL_VISIBLE closure) gtk_accel_map_add_entry (accel_path key mods)

La fonction gtk_accelerator_parse permet de deacutecomposer une chaicircne de caractegraveres de la forme ltControlgtF1 ouencore ltAltgtA en numeacutero de touche et modificateur

En plus des touches pour creacuteer un raccourci clavier nous avons besoin dune fonction agrave appeler lorsque lutilisateurappuie sur les touches speacutecifieacutees gtk_accel_group_connect attend une fonction du type GClosure regardons ladocumentation de gobject pour savoir agrave quoi cela correspond

typedef struct

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 5 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

bull La GLib propose un ensemble de fonctions qui couvrent des domaines aussi vastes que les structures dedonneacutees la gestion des threads et des processus de faccedilon portable ou encore un analyseur syntaxique pourles fichiers XML et bien dautre

bull Pango il sagit de la bibliothegraveque daffichage et de rendue de textes

bull ATK

La bibliothegraveque GTK+ en elle-mecircme utilise une approche orienteacutee objet et repose sur plusieurs couches

bull GObject il sagit de la base de limpleacutementation des objets pour la POO

bull GDK bibliothegraveque graphique de bas niveau

bull GTK+ la bibliothegraveque GTK+ elle-mecircme baseacutee sur lutilisation de widgets (1)

Cest bien sucircr cette derniegravere qui nous inteacuteresse ici mais la glib nous sera aussi dune grande aide

I-C-3 - Pourquoi utiliser GTK+

Effectivement pourquoi choisir dutiliser GTK+ plutocirct quune autre bibliothegraveque pour reacutealiser une interface graphiqueVoici quelques arguments

bull GTK+ est sous licence libre LGPL vous pouvez donc lutiliser pour deacutevelopper des programmes libres oucommerciaux

bull La portabiliteacute GTK+ est disponible sur un grand nombre de systegravemes dont Windows Linux Unix et MacOSX

bull GTK+ est deacuteveloppeacutee en C et pour le langage C cependant elle est disponible pour dautres langages telsque Ada C++ (gracircce agrave gtkmm) Java Perl PHP Python Ruby ou plus reacutecemment C

I-D - Installation

I-D-1 - Windows

Pour pouvoir exeacutecuter une application utilisant GTK+ il faut commencer par installer les binaires Pour faciliter leurinstallation il existe un installeur

Si vous utilisez the Gimp utilisez les runtimes proposeacutees sur le sitehttpwwwgimp-winorg

Pour deacutevelopper une application il faut les bibliothegraveques ainsi que les fichiers den-tecircte disponibles sur gtkorg Pourceux qui utilisent CodeBlocks voici la meacutethode agrave suivre Installation de

I-D-2 - Linux

Sous Linux vous disposez sucircrement dun systegraveme de paquets Il vous faudra installer deux paquets le premiercontenant les fichiers permettant dexeacutecuter des programmes utilisant GTK+ le second paquet contient les fichiersneacutecessaires au deacuteveloppement

Une fois linstallation reacuteussie compilez agrave laide de la commande

gcc -Werror -Wall -W -O2 -ansi -pedantic `pkg-config --cflags --libs gtk+-20` c

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 6 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Tous les codes de ce tutoriel ont eacuteteacute testeacutes sous Linux Debian et Windows XP avecCodeBlocks

I-E - La philosophie GTK+

Voici quelques choix qui ont eacuteteacute faits par leacutequipe de deacuteveloppement de GTK+

bull Les noms de fonctions sont de la forme gtk_type_du_widget_action ceci rend les noms des fonctions tregravesexplicites en contre partie ils peuvent ecirctre tregraves longs

bull Tous les objets manipuleacutes sont des GtkWidget pour que GTK+ veacuterifie quil sagit du bon type dobjet lors delappel agrave une fonction chaque type de widget possegravede une macro de la forme GTK_TYPE_DU_WIDGET agraveutiliser pour transtyper vos widgets

bull La gestion des eacuteveacutenements qui modifient le comportement de lapplication (clique de souris pression dunetouche du clavier) se fait gracircce agrave lutilisation de fonctions de rappel (callback) Pour cela on connecte leswidgets agrave des fonctions qui seront appeleacutees lorsque leacuteveacutenement survient

I-F - Quelques notions de POO

La POO ou Programmation Orienteacutee Objet est un mode de programmation baseacutee sur des objets GTK+ utilisant ceprincipe (2) je vais vous en expliquer les principes de bases

Plutocirct que le deacuteroulement du programme soit reacutegie par une suite dinstruction en POO il est reacutegi par la creacuteationlinteraction et la destruction dobjets en reacutesumeacute la vie des objets qui le composent Un objets est une entiteacute (leparallegravele avec la vie courante est simple un objet pourrait ecirctre un ordinateur) en C on pourrait se repreacutesenter unobjet comme une structure de donneacutees

Un objet est composeacute de proprieacuteteacutes (ce qui correspond agrave nos variables) et de meacutethodes (des fonctions) Pour creacuteerun objet on fait appel agrave son constructeur il sagit dune fonction qui a pour but de creacuteer et dinitialiser lobjet A la finde sa vie lobjet doit ecirctre deacutetruit cest le but du destructeur

Dans la vie courante on peut creacuteer des objets complexes agrave partir de briques de base il est possible de creacuteer denouveaux objets en se basant sur un ou plusieurs objets ce meacutecanisme est appeler heacuteritage (on parle dheacuteritagemultiple lorsquil met en jeu plusieurs objets parents) Lobjet ainsi obtenu heacuterite des proprieacuteteacutes et des meacutethodes deses parents tout en pouvant modifier leur comportement et creacuteer ses propres proprieacuteteacutes et meacutethodes

Lorsque lon souhaite creacuteer un patron pour de futures classes plutocirct que de creacuteer une classe de base qui ne serajamais instancieacutee il est possible de creacuteer une interface

Le dernier concept de POO qui va nous servir dans ce tutoriel est le polymorphisme Ceci permet agrave un objet (prenonspar exemple camion) de se comporter comme lun de ses parents (dans le cas du camion il peut ecirctre vu comme unveacutehicule au mecircme titre quune voiture) Ceci est aussi valable pour des classes impleacutementant la mecircme interface

Pour vous initier aux joies de la programmation orienteacutee objet en C je vous conseille le tutoriel de CGI POO en C

I-G - Notre premier programme

Un programme qui utilise GTK+ est un programme eacutecrit en C avant tout il contient donc le code de base de toutprogramme C

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 7 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

maincinclude ltstdlibhgt

int main (int argc char argv) return EXIT_SUCCESS

Pour pouvoir utiliser les fonctions de GTK+ il faut bien sucircr inclure le fichier den-tecircte correspondant

include ltgtkgtkhgt

La premiegravere chose agrave faire est dinitialiser la machinerie GTK+ gracircce agrave la fonction gtk_init

void gtk_init (int argc char argv)

Cette fonction reccediloit les arguments passeacutes en ligne de commande ceux qui sont speacutecifiques agrave GTK+ sont ensuiteretireacutes de la liste dougrave lutilisation des pointeurs

Ensuite il nous faut creacuteer tous les widgets dont nous avons besoin si neacutecessaire modifier leurs paramegravetres pardeacutefaut les connecter agrave des fonctions callback et ensuite demander leur affichage (tout ceci sera expliciteacute dans lasuite du tutoriel) Une fois la fenecirctre principale creacuteeacutee il suffit de lancer la boucle principale de GTK+

void gtk_main (void)

Cette fonction est une boucle sans fin (seule la fonction gtk_main_quit permet den sortir) qui se charge de geacuterer ledeacuteroulement de notre programme (affichage des widgets envoi de signaux)

Voici donc notre premier programme en CGTK+ qui ne fait rien

maincinclude ltstdlibhgtinclude ltgtkgtkhgt

int main (int argc char argv) Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application

Lancement de la boucle principale gtk_main() return EXIT_SUCCESS

En plus de ne rien faire notre programme ne peut ecirctre termineacute que de faccedilon brutale (Ctrl+C) puisque nous nappelonspas la fonction gtk_main_quit

I-H - Code source

chapitre1zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 8 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

II - Notre premiegravere fenecirctre

II-A - Aperccedilu

II-B - Creacuteation

La fenecirctre principale est repreacutesenteacutee par la classe GtkWindow

La creacuteation dune fenecirctre se fait simplement en appelant le constructeur de cette classe la fonction gtk_window_new

GtkWidget gtk_window_new (GtkWindowType type)

Le seul paramegravetre de cette fonction est le type de fenecirctre souhaiteacute Il ny a que deux possibiliteacutes

bull GTK_WINDOW_TOPLEVEL une fenecirctre classique (cest la base de notre application)

bull GTK_WINDOW_POPUP il sagit dune fenecirctre avec seulement lespace de travail (pas de bordure ni demenu systegraveme)

Cette fonction renvoie un pointeur sur une structure de type GtkWindow (transformer en GtkWidget gracircce aupolymorphisme) qui est lentiteacute qui va nous servir agrave manipuler notre fenecirctre

II-C - Affichage

Si vous essayez deacutecrire un code maintenant vous ne verrez rien pourquoi Tout simplement parce quil faut preacuteciseragrave GTK+ quil faut rendre notre fenecirctre visible gracircce agrave la fonction gtk_widget_show

void gtk_widget_show (GtkWidget widget)

Voici le code qui permet dafficher notre premiegravere fenecirctre

maincinclude ltstdlibhgtinclude ltgtkgtkhgt

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL)

Affichage de la fenetre principale gtk_widget_show (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 9 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Ceux qui se sont essayeacutes agrave la creacuteation dapplications graphiques avec lAPI Windows comprendront la simpliciteacutede ce code

II-D - Destruction

Dans lexemple preacuteceacutedent si vous avez essayeacute de terminer lapplication en fermant la fenecirctre (Alt+F4 ou en cliquantsur la petite croix) vous vous ecirctes peut-ecirctre aperccedilu que lapplication tournait encore en fond cest le mecircme problegravemeque pour le chapitre preacuteceacutedent on ne fait pas appel agrave gtk_main_quit Mais comment appeler cette fonction puisquequune fois gtk_main appeleacutee nous ne pouvons rien faire Cest lagrave quintervient le meacutecanisme des callback A chaqueeacuteveacutenement qui se produit la bibliothegraveque GObject produit un signal si nous souhaitons modifier le comportementpar deacutefaut du signal il suffit de connecter notre fonction callback agrave leacuteveacutenement souhaiteacute

define g_signal_connect(instance detailed_signal c_handler data)

Cette macro permet dintercepter leacuteveacutenement detailed_signal de lobjet instance gracircce agrave la fonction c_handler quidoit ecirctre du type GCallback

void (GCallback) (void)

Les fonctions callback peuvent bien sucircr recevoir des paramegravetres mais leur nature et leur nombre deacutependent ducontexte tout est geacutereacute par la bibliothegraveque GObject Le prototype le plus courant pour une fonction de rappel estle suivant

void callback (GtkWidget p_widget gpointer user_data)

Dont le premier paramegravetre est le widget qui a reccedilu le signal et le second correspond au paramegravetre data de la fonctiong_signal_connect qui nous permet de passer des informations aux fonctions callback Pour finir proprement notreapplication il suffit dintercepter le signal destroy de notre fenecirctre et dy assigner la fonction gtk_main_quit qui neprend pas dargument Voici donc notre premiegravere application fonctionnelle

maincinclude ltstdlibhgtinclude ltgtkgtkhgt

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (gtk_main_quit) NULL)

Affichage de la fenetre principale gtk_widget_show (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

Il est plus courant de creacuteer notre propre fonction de rappel pour quitter le programme ceci permet de libeacuterer lameacutemoire alloueacutee fermer les fichiers ouverts

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 10 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

maincinclude ltstdlibhgtinclude ltgtkgtkhgt

void cb_quit (GtkWidget gpointer)

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (cb_quit) NULL)

Affichage de la fenetre principale gtk_widget_show (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

void cb_quit (GtkWidget p_widget gpointer user_data) gtk_main_quit()

Parametres inutilises (void)p_widget (void)user_data

Le preacutefixe cb_ permet de diffeacuterencier les fonctions callback quil est preacutefeacuterable de regrouper dans un ou plusieursfichiers seacutepareacutes

A la fin de la fonction je transtype les paramegravetres inutiliseacutes pour eacuteviter que moncompilateur mindique des variables non utiliseacutees cest le problegraveme avec les fonctionscallback lAPI nous impose un prototype

II-E - Code source

chapitre2zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 11 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

III - Fermer notre fenecirctre gracircce aux boutons

III-A - Aperccedilu

III-B - Les boutons poussoir

Maintenant que notre programme se termine proprement il est plus convivial de proposer agrave lutilisateur un boutonpour quitter Pour creacuteer un bouton poussoir il existe plusieurs possibiliteacutes

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 premiegravere fonction creacutee un bouton qui peut servir pour contenir nimporte quel autre widget (label image) Si voussouhaitez creacuteer un bouton avec du texte dessus utilisez directement la seconde fonction qui prend en argument letexte agrave afficher Si vous souhaitez ajouter un raccourci clavier (accessible avec la touche Alt) la troisiegraveme fonctionpermet den speacutecifier un en faisant preacuteceacuteder une lettre (geacuteneacuteralement la premiegravere) dun underscore _ (si voussouhaitez afficher le caractegravere _ il faut en mettre deux) Enfin la derniegravere fonction permet dutiliser les Stock Itemsqui sont un ensemble deacuteleacutements preacutedeacutefinis par GTK+ pour les menus et barres doutils Le seul paramegravetre de cettefonction est le nom de leacuteleacutement et GTK+ se charge dafficher licocircne approprieacutee ainsi que le texte suivant la languechoisie et un raccourci

Cest bien sucircr cette derniegravere fonction que nous allons utiliser et ce le plus souvent possible Voici le code pour creacuteerun tel bouton

maincGtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_QUIT)

Pour obtenir tous les types de stocks items disponibles GtkStockItem

Bien sucircr comme pour la fenecirctre si lon veut voir quelque chose il faut demander agrave GTK+ dafficher notre widget

maincgtk_widget_show (p_button)

Mais pas seulement En effet il faut preacuteciser agrave GTK+ ougrave doit ecirctre afficheacute notre bouton Pour cela la classe GtkWindowest deacuteriveacutee de la classe GtkContainer qui est comme son nom le laisse penser un conteneur pour widget Pourajouter un widget il suffit de faire appel agrave la fonction gtk_container_add

void gtk_container_add (GtkContainer container GtkWidget widget)

Le premier paramegravetre de cette fonction est un GtkContainer or nous souhaitons passer notre fenecirctre qui est unGtkWidget pour ne pas avoir de problegravemes il faut utiliser le systegraveme de macro offert par GTK+ pour transtyper notreGtkWidget en GtkContainer (eh oui en C le polymorphisme a ses limites)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 12 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

maincgtk_container_add (GTK_CONTAINER (p_window) p_button)

Ce meacutecanisme de transtypage permet agrave GTK+ de veacuterifier que notre GtkWidget est bien compatible avec lutilisationque lon souhaite en faire En cas deacutechec GTK+ nous preacutevient en affichant un message dans la console

(gtk_boutonexe1044) Gtk-CRITICAL gtk_container_add assertion `GTK_IS_CONTAINER (container) failed

Pour finir il faut connecter notre bouton pour appeler notre fonction cb_quit lorsque lutilisateur clic dessus (ce quicorrespond agrave leacuteveacutenement clicked)

g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_quit) NULL)

Pour eacuteviter dappeler la fonction gtk_widget_show pour tous les widgets de notreapplication on peut se contenter dun seul appel agrave la fonction gtk_widget_show_all quipermet dafficher tous les widgets contenus dans celui passeacute agrave la fonction

maincinclude ltstdlibhgtinclude ltgtkgtkhgtinclude callbackh

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (cb_quit) NULL)

GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_QUIT) gtk_container_add (GTK_CONTAINER (p_window) p_button) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_quit) NULL)

Affichage de la fenetre principale gtk_widget_show_all (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

III-C - Code source

chapitre3zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 13 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IV - Comment afficher plusieurs widgets

IV-A - Aperccedilu

IV-B - Le problegraveme

Dans la partie preacuteceacutedente nous avons reacuteussi agrave afficher un bouton dans la fenecirctre de notre application Si vous avezessayeacute dajouter un second widget GTK+ agrave ducirc vous reacutepondre poliment

(gtk_boxexe492) Gtk-WARNING Attempting to add a widget with typeGtkButton to a GtkWindow but as a GtkBin subclass a GtkWindow can only containone widget at a time it already contains a widget of type GtkButton

Les plus anglophiles dentre vous auront compris que GTK+ naccepte pas lajout un second widget dans notre fenecirctretout simplement parce quil y en a deacutejagrave un et que la sous classe GtkBin (classe megravere de notre GtkWindow) ne peutcontenir quun seul widget

IV-C - La solutions

Pour contourner ce problegraveme il faut commencer par creacuteer un widget qui accepte den contenir plusieurs autrespour ensuite y ajouter tout ce dont nous avons besoin Pour linstant nous utiliserons quun seul widget (il existetrois classes qui permettent ceci) il sagit des GtkBox Il sagit de la meacutethode que jutilise le plus souvent Ce nestpeut-ecirctre pas la plus simple agrave maicirctriser mais elle extrecircmement souple et puissante Elle consiste agrave creacuteer une boicirctepuis agrave y ajouter les widgets les uns apregraves les autres (soit au deacutebut soit agrave la fin) Il existe deux classes heacuteritant deGtkBox les GtkVBox qui empilent les widgets dans le sens vertical et les GtkHBox qui font de mecircme mais dansle sens horizontal Les fonctions pour manipuler ces deux classes sont les mecircmes seule la fonction pour les creacuteerportent un nom diffeacuterent

GtkWidget gtk_vbox_new (gboolean homogeneous gint spacing)GtkWidget gtk_hbox_new (gboolean homogeneous gint spacing)

Le paramegravetre homogeneous permet de reacuteserver pour chaque widget une zone de taille identique (zone que le widgetnest pas obligeacute de remplir) et spacing permet dajouter une bordure en pixels (espacement autour de la GtkBox)Ensuite il suffit dajouter les diffeacuterents widgets gracircce aux fonctions

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)

Qui ajoutent reacuteciproquement le widget child au deacutebut et agrave la fin de box Le paramegravetre expand permet au widget davoirle plus de place possible (si le paramegravetre homogeneous vaut TRUE cette option a aucun effet) Si plusieurs widgetont ce paramegravetre agrave TRUE ils se partagent de faccedilon eacutegale lespace Loption fill permet au widget de remplir toutlespace qui lui ait reacuteserveacute

Pour reacuteellement comprendre linfluence de ces paramegravetres il faut faire des tests en modifiant un agrave un chaqueparamegravetre et observer les effets dun redimentionnement de la fenecirctre principale

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 14 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Le plus gecircnant avec cette meacutethode cest quil faut jongler entre les GtkHBox et les GtkVBox en les imbriquant pourobtenir le reacutesultat souhaiter nheacutesitez pas agrave utiliser une feuille et un crayon )

Pour en revenir agrave notre eacutediteur de texte nous allons preacuteparer notre application agrave contenir les futurs widgetsNous utilisons un GtkVBox pour lensemble des widgets (il sagit de la boicircte principale qui pourra contenir dautresGtkContainer selon nos besoins)

maincinclude ltstdlibhgtinclude ltgtkgtkhgtinclude callbackh

int main (int argc char argv) GtkWidget p_window = NULL GtkWidget p_main_box = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (cb_quit) NULL)

Creation du conteneur principal p_main_box = gtk_vbox_new (FALSE 0) gtk_container_add (GTK_CONTAINER (p_window) p_main_box)

Creation du bouton Quitter GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_QUIT) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_quit) NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_button FALSE FALSE 0)

Affichage de la fenetre principale gtk_widget_show_all (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

IV-D - Code source

chapitre4zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 15 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

V - Afficher le contenue dun fichier

V-A - Aperccedilu

Cliquez pour agrandir

V-B - Saisir du texte

Les choses seacuterieuses vont commencer il sagit de mettre en place le widget qui va nous permettre dafficher etdeacutediter du texte Il sagit de la classe GtkTextView Gracircce agrave GTK+ la mise en place est toujours aussi simple

mainc GtkWidget p_text_view = NULL Creation de la zone de texte p_text_view = gtk_text_view_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_text_view TRUE TRUE 0)

Comme il sagit de la partie centrale de notre application nous demandons agrave ce quelle prenne le plus de placepossible (gracircce agrave la fonction gtk_box_pack_start)

Puisque nous voulons afficher les boutons en dessous de la zone de texte il faut ajouter ce morceau de code avantcelui creacuteant le bouton

V-C - Ouvrir un fichier

Maintenant nous avons une belle zone de texte il faut la remplir avec le contenu dun fichier Pour ce faire nousallons commencer par ajouter un bouton ouvrir

mainc Creation du bouton Ouvrir GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_OPEN) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_open) p_text_view) gtk_box_pack_start (GTK_BOX (p_main_box) p_button FALSE FALSE 0)

Si vous exeacutecutez le programme maintenant (3) vous remarquerez que les boutons sont ajouteacutes les uns en dessousdes autres ce qui diminue la zone de saisie (avec deux boutons ce nest pas gecircnant mais au bout dune dizaineccedila risque decirctre probleacutematique) Pour pallier ce problegraveme nous allons utiliser un nouveau style de GtkBox lesGtkButtonBox qui sont preacutevus pour contenir des boutons (ccedila tombe plutocirct bien D) Donc pour eacuteviter de diminuerla zone de saisie et comme nous avons de la place en largueur nous allons utiliser un GtkHButtonBox qui va ecirctreinclus dans la p_main_box Voici les modifications agrave effectuer

mainc GtkWidget p_button_box = NULL Creation du conteneur pour les boutons p_button_box = gtk_hbutton_box_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_button_box FALSE FALSE 0)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 16 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc gtk_box_pack_start (GTK_BOX (p_button_box) p_button FALSE FALSE 0) gtk_box_pack_start (GTK_BOX (p_button_box) p_button FALSE FALSE 0)

Maintenant il nous reste plus quagrave creacuteer la fonction cb_open dans le fichier callbackc pour linstant nous nouscontenterons douvrir toujours le mecircme fichier nous verrons plus tard comment laisser le choix agrave lutilisateur

callbackcdefine DEFAULT_FILE mainc

void cb_open (GtkWidget p_widget gpointer user_data) open_file (DEFAULT_FILE GTK_TEXT_VIEW (user_data))

Parametre inutilise (void)p_widget

Vous aurez compris que lon va deacuteleacuteguer tout le travail agrave la fonction open_file qui devra ouvrir le fichier dont le nomest passeacute en premier paramegravetre pour lafficher dans le GktTextView

Jai fait ce choix pour deux raisons le code dune fonction callback peut ecirctre tregraves conseacutequent (surtout si lon souhaitequelle affiche une boicircte de dialogue) et aussi parce que cb_open nest peut ecirctre pas la seule fonction agrave copierun fichier dans un GtkTextView (par exemple lors de la creacuteation dun nouveau fichier lon peut vouloir copier unsquelette de fichier)

Pour copier notre fichier plutocirct que dutiliser la fonction fgets nous allons nous servir de la glib (4) qui proposela fonction

gboolean g_file_get_contents (const gchar filename gchar contents gsize length GError error)

Qui nous renvoit le contenu du fichier nommeacute filename dans le tampon contents Il est possible de reacutecupeacuterer lenombre de caractegraveres copieacutes et retourne TRUE en cas de succegraves sinon FALSE et dans ce cas une structure de typeGError est creacutee pour en savoir plus sur le type derreur rencontreacute

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView else print_warning (Impossible douvrir le fichier sn file_name)

Je pense quun certain nombre dexplications simpose (surtout si je vais trop vite nheacutesitez pas agrave marrecircter )

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 17 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

bull g_return_if_fail est une macro qui peut ecirctre compareacutee agrave assert sauf quelle se contente de sortir de la fonctionsi lexpression passeacutee en paramegravetre est fausse Cest une meacutethode pratique pour veacuterifier la validiteacute desparamegravetres (si la fonction doit retourne une valeur utiliseacute plutocirct g_return_val_if_fail qui prend un secondparamegravetre la valeur agrave retourner)

bull Ensuite on essaie de reacutecupeacuterer le contenu de notre fichier

bull Si cela eacutechoue nous le signalons agrave lutilisateur agrave laide de la fonction print_warning

bull Le type gchar est une redeacutefinition du type char par la glib (il en va de mecircme pour tous les autres types du C)privileacutegiez ces types lorsque vous utilisez des fonctions de cette bibliothegraveques

Mais quest-ce donc cette fonction print_warning Cest une fonction que nous allons creacuteer semblable agrave printf quisignalera agrave lutilisateur quune erreur non critique est survenue Comme nous navons pas encore abordeacute les boicirctesde dialogue pour afficher un message il sagira pour linstant dune simple redeacutefinition de printf Pendant que noussommes dans laffichage des messages nous allons aussi creacuteer deux fonctions print_info et print_error qui vontrespectivement afficher un message dinformation et un message derreur critique (ce qui entraicircne la terminaison duprogramme) tout ceci dans un nouveau fichier errorc

errorhifndef H_ERRORdefine H_ERROR

void print_info (char )void print_warning (char )void print_error (char )

endif not H_ERROR

errorcinclude ltstdarghgtinclude ltstdiohgtinclude ltstdlibhgtinclude errorh

void print_info (char format ) va_list va

va_start (va format) printf (Information ) vprintf (format va) printf (n)

void print_warning (char format ) va_list va

va_start (va format) fprintf (stderr Erreur ) vfprintf (stderr format va) fprintf (stderr n)

void print_error (char format ) va_list va

va_start (va format) fprintf (stderr Erreur fatale ) vfprintf (stderr format va) fprintf (stderr n) exit (EXIT_FAILURE)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 18 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

Pour en finir avec louverture dun fichier il nous reste agrave copier contents dans le GtkTextView En fait le GtkTextViewne gegravere que la forme pour modifier le contenu il faut passer par les GtkTextBuffer Commenccedilons donc par reacutecupeacutererce fameux GtkTextBuffer

callbackc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (p_text_view)

Et pour finir on utilise la fonction

void gtk_text_buffer_insert (GtkTextBuffer buffer GtkTextIter iter const gchar text gint len)

Reacutecapitulons buffer est le GtkTextBuffer que lon vient de reacutecupeacuterer text cest le texte agrave afficher et len la taille dece dernier (ou -1 sil sagit dune chaicircne de caractegraveres au sens du langage C)

Mais quest-ce donc ce GtkTextIter On peut voir cela comme un curseur virtuel qui indique la position agrave laquelleeffectuer linsertion de texte dans le GtkTextBuffer (5) Allons voir ce que la documentation peut nous apprendreagrave leur sujet (6)

typedef struct GtkTextIter is an opaque datatype ignore all these fields Initialize the iter with gtk_text_buffer_get_iter_ functions GtkTextIter

Voilagrave on a notre solution suffit de rechercher les fonctions commenccedilant par gtk_text_buffer_get_iter_ voici la liste

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)

La fonction gtk_text_buffer_get_iter_at_line fait parfaitement laffaire

callbackc GtkTextIter iter

gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1)

Cependant si vous ne voulez pas avoir de problegravemes avec le codage des caractegraveres il vaut mieux convertir le codagelocal vers utf8 Voici le reacutesultat final

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 19 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gchar utf8 = NULL GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_text_buffer_insert (p_text_buffer ampiter utf8 -1) g_free (utf8) utf8 = NULL

V-D - La petite touche finale

Pour finir cette laborieuse partie sur une petite touche estheacutetique nous allons demander agrave GTK+ de nous lancerlapplication en plein eacutecran Pour se faire il suffit dajouter lors de la creacuteation de la fenecirctre principale

maincgtk_window_maximize (GTK_WINDOW (p_window))

On peut mecircme se permettre une pointe dexcentriciteacute en modifiant le titre de notre fenecirctre

maincgtk_window_set_title (GTK_WINDOW (p_window) Editeur de texte en GTK+)

V-E - Code source

chapitre5zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 20 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VI - Choisir un fichier

VI-A - Aperccedilu

Cliquez pour agrandir

VI-B - Utilisation dun GtkFileChooserFile

Jusquagrave preacutesent lutilisateur navait pas le choix quant au fichier agrave ouvrir heureusement GTK+ vient agrave notre aide gracircceau widget GtkFileChooserFile qui est tout simplement une boicircte de dialogue qui propose agrave lutilisateur de seacutelectionnerun fichier dans son arborescence disque

Commenccedilons par creacuteer notre boicircte de dialogue dans la fonction cb_open

callbackcvoid cb_open (GtkWidget p_widget gpointer user_data) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Ouvrir un fichier NULL GTK_FILE_CHOOSER_ACTION_OPEN GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_OPEN GTK_RESPONSE_ACCEPT NULL)

Cette fonction neacutecessite le titre de la boicircte de dialogue une fenecirctre parente le type daction (ici on souhaite ouvrir unfichier GTK+ autorisera lutilisateur agrave seacutelectionner uniquement les fichiers existants) Pour finir il sagit dun couple devaleurs GTK_STOCK_ITEMGTK_STOCK_RESPONSE qui permet de creacuteer un bouton utilisant le stock ID speacutecifieacuteet lorsque celui-ci est cliqueacute la fonction servant agrave lancer la boicircte de dialogue retournera le reacuteponse ID correspondantIl existe une seacuterie de valeurs deacutefinies par GTK+ quil est conseilleacute dutiliser

typedef enum GTK returns this if a response widget has no response_id or if the dialog gets programmatically hidden or destroyed GTK_RESPONSE_NONE = -1

GTK wont return these unless you pass them in as the response for an action widget They are for your convenience GTK_RESPONSE_REJECT = -2 GTK_RESPONSE_ACCEPT = -3

If the dialog is deleted GTK_RESPONSE_DELETE_EVENT = -4

These are returned from GTK dialogs and you can also use them yourself if you like GTK_RESPONSE_OK = -5 GTK_RESPONSE_CANCEL = -6 GTK_RESPONSE_CLOSE = -7 GTK_RESPONSE_YES = -8

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 21 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GTK_RESPONSE_NO = -9 GTK_RESPONSE_APPLY = -10 GTK_RESPONSE_HELP = -11 GtkResponseType

Nous indiquons la fin des couples stock idreacuteponse id avec la valeur NULL

Une fois la boicircte de dialogue creacuteee on demande agrave GTK+ de lafficher gracircce agrave la fonction gtk_dialog_run puis onreacutecupegravere sa valeur de retour qui correspond au bouton cliqueacute par lutilisateur

callbackc if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

Ici ce qui nous inteacuteresse cest lorsque que lutilisateur clique sur le bouton ouvrir (donc gtk_dialog_run renvoieGTK_RESPONSE_ACCEPT) dans ce cas il nous suffit de reacutecupeacuterer le nom du fichier seacutelectionneacute puis de louvrir

callbackc gchar file_name = NULL

file_name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) open_file (file_name GTK_TEXT_VIEW (user_data)) g_free (file_name) file_name = NULL

Pour finir dans tous les cas on noublie pas de deacutetruire la boicircte de dialogue

callbackc gtk_widget_destroy (p_dialog)

Et voilagrave le travail lutilisateur peut ouvrir le fichier quil souhaite

VI-C - Code source

chapitre6zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 22 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VII - Interlude

Avant daller plus loin dans lameacutelioration de linterface de notre eacutediteur il est neacutecessaire de modifier sonfonctionnement interne (ne vous inquieacutetez je nai pas dit chambouler) en effet souvenez-vous dans lintroduction jaieacutevoqueacute la possibiliteacutes douvrir plusieurs documents gracircce agrave un systegraveme donglets Pour cela il faut sauvegarder lesproprieacuteteacutes de chaque document ouvert Pris agrave temps ce genre de modification nest pas trop lourde mais si nousattendons cela risque de devenir un vrai casse tecircte

Pour cela nous allons utiliser une structure de donneacutee pour chaque document ouvert qui devra garder en meacutemoirele chemin complet du fichier (ou NULL si le document nest pas encore sauvegarder) sil agrave eacutetait modifier depuis laderniegravere sauvegarde et le GtkTextView qui sert agrave son affichage Voici donc la structure qui va nous servir

documenthtypedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

Sachant que nous serons ameneacute agrave stocker plusieurs occurrences de cette structure il serait bon de reacutefleacutechir degravesmaintenant agrave la structure de donneacutee agrave utiliser pour les stocker La premiegravere ideacutee qui vient agrave lesprit est un tableaualloueacute dynamiquement cependant lutilisateur peut souhaiter fermer un document qui se trouve au milieu on estalors obligeacute de deacutecaler toutes les cellules en amont Dans ce cas il parait naturel dutiliser une liste chaicircneacutee Parchance la glib propose une bibliothegraveque de gestion des listes chaicircneacutees cela nous fera gagner du temps le momentvenu Pour linstant on se contente de creacuteer une structure de donneacutees qui contiendra tous les documents ouverts(stockeacutee dans une GList) et un pointeur sur le document actif (actuellement comme nous navons quun documentouvert en mecircme temps on manipulera uniquement ce pointeur)

documenthtypedef struct GList tous document_t actif docs_t

Maintenant se pose le problegraveme de savoir comment transmettre cette structure On pourrait se servir du paramegravetreuser_data preacutesent dans toutes les fonctions callback mais certaines fonctions utilise deacutejagrave ce paramegravetre (la fonctioncb_open par exemple) il faudrait creacuteer un champs suppleacutementaire dans notre structure documents_s Une solutionplus simple est de creacuteer une variable globale agrave lensemble du programme Ceux qui passe reacuteguliegraverement sur le forumC savent que cest fortement deacuteconseilleacute mais ici nous nous trouvons dans lune des rares exceptions agrave la regravegle Detoute faccedilon cela revient au mecircme que de passer ladresse de notre structure agrave toutes les fonctions callback Nousdeacutefinissons donc un nouveau fichier den-tecircte

documenthifndef H_DOCUMENTdefine H_DOCUMENT

include ltgtkgtkhgt

typedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 23 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

documenthtypedef struct GList tous document_t actif docs_t

extern docs_t docs

endif not H_DOCUMENT

Et dans le fichier mainc

maincinclude documenth

docs_t docs = NULL NULL

Pour linstant la seule fonction qui modifie leacutetat dun document est la fonction open_file il faut donc inclure documenthdans callbackc et modifier leacutegegraverement la fonction pour enregistrer le document ouvert

callbackc if (g_file_get_contents (file_name ampcontents NULL NULL)) Pour linstant il faut allouer la memoire par la suite on modifira simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = g_strdup (file_name) Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = p_text_view Le document vient detre ouvert il nest donc pas modifie docsactif-gtsauve = TRUE

Ne soyez pas choqueacute si je ne teste pas le retour de la fonction g_malloc pour veacuterifier quilnest pas NULL En effet cette derniegravere met fin agrave lapplication si lallocation eacutechoue

VII-A - Code source

chapitre7zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 24 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VIII - Sauvegarder les modification

VIII-A - Aperccedilu

Cliquez pour agrandir

VIII-B - Enregistrer

Avant de pouvoir sauvegarder un document il faut quil soit modifieacute Comment savoir que le contenu du fichier a eacuteteacutemodifier Gracircce au signal changed du GtkTextBuffer que nous interceptons gracircce agrave la fonction cb_modifie

mainc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (p_text_view)) g_signal_connect (G_OBJECT (p_text_buffer) changed G_CALLBACK (cb_modifie) NULL)

Cette derniegravere modifie simplement le champ sauve du document

callbackcvoid cb_modifie (GtkWidget p_widget gpointer user_data) if (docsactif) docsactif-gtsauve = FALSE

Pour la sauvegarde il faut distinguer deux cas soit il sagit de la premiegravere sauvegarde du fichier il faut alors demanderle nom du fichier agrave lutilisateur (cela ressemble fortement agrave louverture dun fichier) soit le fichier est deacutejagrave preacutesent surle disque il suffit de remplacer son contenu par celui du GtkTextViewer Nous avons convenu quun fichier qui neacutetaitpas encore enregistreacute avait sa proprieacuteteacute chemin agrave NULL

Bien sucircr cela na lieu que si un fichier est ouvert et quil a eacuteteacute modifieacute depuis sa derniegravere sauvegarde

callbackcvoid cb_save (GtkWidget p_widget gpointer user_data) if (docsactif) if (docsactif-gtsauve) Le fichier na pas encore ete enregistre if (docsactif-gtchemin) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Sauvegarder le fichier NULL GTK_FILE_CHOOSER_ACTION_SAVE GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_SAVE GTK_RESPONSE_ACCEPT NULL) if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 25 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc docsactif-gtchemin = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) gtk_widget_destroy (p_dialog) Soit le fichier a deja ete enregistre soit lutilisateur vient de nous fournir son nouvel enplacement on peut donc lenregistrer if (docsactif-gtchemin) else print_warning (Aucun document ouvert)

Il nous reste plus quagrave reacutecupeacuterer le contenu du GtkTextViewer et le copier dans le fichier chemin sans oublier dereconvertir le texte dans le codage local

callbackc FILE fichier = NULL

fichier = fopen (docsactif-gtchemin w) if (fichier) gchar contents = NULL gchar locale = NULL GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) contents = gtk_text_buffer_get_text (p_text_buffer ampstart ampend FALSE) locale = g_locale_from_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL fprintf (fichier s locale) g_free (locale) locale = NULL fclose (fichier) fichier = NULL docsactif-gtsauve = TRUE else print_warning (Impossible de sauvegarder le fichier s docsactif-gtchemin)

Le dernier paramegravetre de la fonction gtk_text_buffer_get_text est mis agrave FALSE car nous ne voulons pas enregistrerles caractegraveres invisibles preacutesent dans le GtkTextBuffer Ces caractegraveres servent agrave mettre en forme le texte (taillecouleur) nous pourrions creacuteer un nouveau format de fichier pour enregistrer la mise en forme

VIII-C - Enregistrer sous

Pour enregistrer notre document sous un autre nom il suffit de faire croire agrave cb_save que le document na pas encoreeacutetait enregistreacute tout simplement en changeant chemin agrave NULL et sauve agrave FALSE

callbackcvoid cb_saveas (GtkWidget p_widget gpointer user_data)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 26 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (docsactif) document_t tmp = docsactif

docsactif-gtchemin = NULL docsactif-gtsauve = FALSE cb_save (p_widget user_data) if (docsactif-gtsauve) (docsactif) = tmp else print_warning (Aucun document ouvert)

Il ne faut pas oublier que lutilisateur peut annuler lenregistrement de ce fait nous sauvegardons leacutetat du documentet si la sauvegarde na pas eu lieu on le restaure

VIII-D - Code source

chapitre8zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 27 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IX - Creacuteer un nouveau document

IX-A - Aperccedilu

Cliquez pour agrandir

IX-B - Nouveau fichier

Maintenant que lutilisateur peut ouvrir et fermer un fichier il est inteacuteressant de lui donner la possibiliteacute den creacuteerun nouveau Je ne reviens pas sur la creacuteation du bouton (ccedila devrait deacutejagrave ecirctre fait D) passons directement agrave lafonction cb_new

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) Pour linstant il faut allouer la memoire par la suite on modifiera simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = NULL Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = GTK_TEXT_VIEW (user_data) Le document vient detre creer il nest donc pas modifie docsactif-gtsauve = TRUE gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Je ne sais pas vous mais pour ma part jai fait un copiercoller de la fonction open_file Et oui ouvrir un document peutse reacutesumer agrave creacuteer un document vide puis remplir le GtkTextView avec le fichier souhaiteacute On peut donc simplifiernotre fonction open_file ainsi

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

cb_new (NULL p_text_view) gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE) p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1) Nous sommes obliges de remetre sauve a TRUE car linsertion du contenu du fichier dans le GtkTextView a appele cb_modfie docsactif-gtsauve = TRUE else print_warning (Impossible douvrir le fichier sn file_name)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 28 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc

Cest beau la factorisation du code Par contre nous sommes obligeacutes de remettre sauve agrave TRUE car nous avonsmodifieacute le GtkTextBuffer

IX-C - Code source

chapitre9zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 29 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

X - Fermer

X-A - Aperccedilu

Cliquez pour agrandir

X-B - Fermer un fichier

Maintenant que nous allouons de la meacutemoire il faut la libeacuterer agrave un endroit Logiquement cela va ecirctre fait agrave la fermeturedu document en guise dexercice je vous laisse creacuteer le bouton dans notre boicircte agrave bouton

Allez je vous aide le stock id correspondant est GTK_STOCK_CLOSE

Voilagrave maintenant si tout cest bien passeacute vous devriez ecirctre arriveacute dans le fichier callbackc avec quelque choseressemblant agrave

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data)

Lorsque lon ferme un document il faut vider le GtkTextView (avec les onglets on se contentera de le supprimer)pour cela il faut reacutecupeacuterer le deacutebut et la fin du GtkTextBuffer et demander agrave GTK+ de supprimer tout ce qui ce trouveentre les deux iteacuterateurs

callbackc Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) gtk_text_buffer_delete (p_text_buffer ampstart ampend) else print_warning (Aucun document ouvert)

Bien sucircr il ne faut pas oublier de libeacuterer la meacutemoire

callbackc g_free (docsactif-gtchemin) docsactif-gtchemin = NULL docsactif-gtp_text_view = NULL g_free (docsactif) docsactif = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 30 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour symboliser la fermeture dun document nous deacutesactivons le GtkTextView lors de la fermeture (ne pas oublierde le faire aussi dans mainc)

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) FALSE)

Et nous le reacuteactivons lors de louverture si celle si reacuteussie

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Lorsque lutilisateur quitte lapplication il faut bien sucircr fermer le document sil y en a un ouvert

void cb_quit (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data) gtk_main_quit()

Et aussi lorsquil creacuteeacute un nouveau document (et par conseacutequent lorsquil ouvre un fichier puisque lon fait appel agravecb_new)

void cb_new (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data)

X-C - Enregistrer avant de fermer

Si le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde geacuteneacuteralement le programme le signale agrave lutilisateur etlui propose de sauvegarder ou dannuler la fermeture Pour se faire nous devons modifier la fonction cb_close avantde fermer le document nous allons afficher une boicircte de dialogue

Pour creacuteer une boicircte de dialogue simplement il existe la classe GtkDialog et comme nous avons besoin de boutons(pour que lutilisateur fasse son choix) nous allons creacuteer notre boicircte avec la fonction

GtkWidget gtk_dialog_new_with_buttons (const gchar title GtkWindow parent GtkDialogFlags flags const gchar first_button_text )

Nous retrouvons les mecircmes options que pour le GtkFileChooserDialog mis agrave part option du type GtkDialogFlags

typedef enum GTK_DIALOG_MODAL = 1 ltlt 0 appel gtk_window_set_modal (win TRUE) GTK_DIALOG_DESTROY_WITH_PARENT = 1 ltlt 1 appel gtk_window_set_destroy_with_parent () GTK_DIALOG_NO_SEPARATOR = 1 ltlt 2 Pas de barre de separation au dessus des boutons GtkDialogFlags

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 31 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Nous nous contenterons de rendre notre fenecirctre modale (7)

Pour avoir accegraves agrave notre fenecirctre principale nous ajoutons un champs p_main_window agrave notre structure globaledocs_t que nous initialisons dans la fonction main

mainc docsp_main_window = GTK_WINDOW (p_window)

Il nous reste plus qua creacuteer notre boicircte de dialogue avec trois boutons Oui Non Annuler

callbackc if (docsactif-gtsauve) GtkWidget p_dialog = NULL

p_dialog = gtk_dialog_new_with_buttons (Sauvegarder docsp_main_window GTK_DIALOG_MODAL GTK_STOCK_YES GTK_RESPONSE_YES GTK_STOCK_NO GTK_RESPONSE_NO GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL NULL)

Nous obtenons donc une structure de type GtkDialog

typedef struct GtkWidget vbox GtkWidget action_area GtkDialog

Nous remarquons que cette structure contient deux membres qui permettent dacceacuteder agrave une GtkBox ougrave nous allonsajouter le contenu de la fenecirctre et agrave la partie contenant les boutons

Ensuite la construction de la fenecirctre est identique agrave celle de la fenecirctre principale ici nous nous contenterons dajouterun GtkLabel

callbackc GtkWidget p_label = NULL p_label = gtk_label_new (Voulez-vous sauvegarder les modifications ) gtk_box_pack_start (GTK_BOX (GTK_DIALOG (p_dialog)-gtvbox) p_label TRUE TRUE 0)

Une fois notre fenecirctre precircte il suffit de faire appel agrave la fonction gtk_dialog_run qui va afficher notre GtkDialog et nousretourner le reacuteponse id correspondant au bouton cliqueacute par lutilisateur

callbackc switch (gtk_dialog_run (GTK_DIALOG (p_dialog))) case GTK_RESPONSE_YES cb_save (p_widget user_data) break case GTK_RESPONSE_NO break case GTK_RESPONSE_CANCEL gtk_widget_destroy (p_dialog) return break

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 32 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc gtk_widget_destroy (p_dialog)

Si lutilisateur clique sur non on ne fait rien (le document sera simplement fermeacute) sur oui on enregistre avant defermer et pour finir sil annule on quitte la fonction

X-D - Code source

chapitre10zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 33 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XI - Les barres de deacutefilement

XI-A - Aperccedilu

Cliquez pour agrandir

XI-B - Ajouter des barres de deacutefilement

Apregraves le dernier chapitre quelque peu laborieux voici une partie plus simple mais qui va rendre notre applicationplus pratique En effet si vous avez essayeacute douvrir un fichier de grande taille vous avez pu remarquer que pourpouvoir lire la fin du fichier il fallait utiliser les touches du clavier pas tregraves convivial

Pour rendre la navigation plus aiseacutee on utilise des barres de deacutefilement

mainc GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_scrolled_window TRUE TRUE 0)

Creation de la zone de texte gtk_container_add (GTK_CONTAINER (p_scrolled_window) p_text_view)

Le constructeur de notre GtkScrolledWindow prend en argument deux GtkAdjustment qui permettent de deacutefinirdiffeacuterentes proprieacuteteacutes de la barre de deacutefilement (taille dune page la position de deacutepart) nous laissons GTK+ faireen passant NULL

Cest un bon deacutebut mais estheacutetiquement on peut faire mieux mecircme sil nest pas utile davoir une barre de deacutefilementelle est quand mecircme afficheacutee On peut demander agrave GTK+ de les afficher que si cela est neacutecessaire

mainc gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC)

En fait nous avons de la chance car la classe GtkTextView fait partie des widget qui supporte de faccedilon native les barresde deacutefilement Comment le savoir Ce genre de widget possegravede une ou deux proprieacuteteacutes de type GtkAdjustment (unepour la barre verticale lautre pour la barre horizontale) Actuellement seulement trois classes en sont capables lesGtkTextView les GtkTreeView et les GtkLayout

Comment faire pour les autres widgets Il faut passer par une classe adaptateur GtkViewport afin de creacuteer lesGtkAdjustment

XI-C - Code source

chapitre11zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 34 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XII - Les menus

XII-A - Aperccedilu

Cliquez pour agrandir

XII-B - Creacuteation du menu

Pour simplifier nous avons utiliseacute des boutons pour permettre agrave lutilisateur de creacuteer un document ouvrir un fichierMais il est plus courant dutiliser un menu pour afficher ces options GTK+ propose trois maniegraveres de creacuteer un menu

bull GtkItemFactory cette meacutethode est obsolegravete depuis la version 24 de GTK+

bull GtkUIManager cest ce quon appel une usine agrave gaz pour en savoir plus vous pouvez vous reporter aututoriel Utilisation de GtkUIManager

bull GtkMenu cest ce widget que nous allons eacutetudier il permet de creacuteer un menu manuellement (agrave lopposeacute deGtkUIManager)

Un menu selon GTK+ est composeacute de plusieurs eacuteleacutements

bull GtkMenuBar la barre de menu elle-mecircme

bull GtkMenu la partie deacuteroulante qui contient les diffeacuterents eacuteleacutements

bull GtkMenuItem cest sur ce widget que lutilisateur clique pour lancer une action

Pour commencer faisons linventaire de ce que nous avons besoin

bull Un GtkMenuBar qui sert de base au menu

bull Un GtkMenu pour commencer nous nous aurons dun menu Fichier

bull Six GtkMenuItem pour remplacer nos six boutons

Commenccedilons par la creacuteation du menu nous mettons ce code dans un nouveau fichier dont seul la fonction menu_newsera accessible

menucGtkMenuBar menu_new (gpointer user_data) GtkWidget p_menu_bar = NULL

p_menu_bar = gtk_menu_bar_new () return GTK_MENU_BAR (p_menu_bar)

Le paramegravetre user_data nous servira lors de la connexion des callbacks (nous en avons besoin pour les fonctionscb_new et cb_open)

Ensuite nous allons creacuteer notre sous menu Fichier

menuc Menu Fichier

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 35 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

menuc GtkWidget p_menu = NULL GtkWidget p_menu_item = NULL

p_menu = gtk_menu_new () p_menu_item = gtk_menu_item_new_with_mnemonic (_Fichier) gtk_menu_item_set_submenu (GTK_MENU_ITEM (p_menu_item) p_menu) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu_bar) p_menu_item) return GTK_MENU_BAR (p_menu_bar)

Un sous menu est en fait un GtkMenuItem auquel on assigne un GtkMenu Il faut bien sucircr terminer la creacuteation dusous-menu en lajoutant agrave la barre de menu

Pour finir nous creacuteons les eacuteleacutements du menu les GtkItemMenu Il existe plusieurs types deacuteleacutements (comparableaux diffeacuterents types de bouton) pour commencer nous nutiliserons que le type de base Comme cette opeacuteration estreacutepeacutetitive nous allons creacuteer une fonction pour le faire

menucstatic void menu_item_new (GtkMenu p_menu const gchar title GCallback callback gpointer user_data) GtkWidget p_menu_item = NULL

p_menu_item = gtk_menu_item_new_with_mnemonic (title) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu) p_menu_item) g_signal_connect (G_OBJECT (p_menu_item) activate callback user_data)

Pour permettre agrave lutilisateur dacceacuteder aux diffeacuterents eacuteleacutements du menu agrave laide de la touche ltAltgt nous utilisonsdes mneacutemoniques par exemple pour quitter leacutediteur il suffit de faite Alt+F puis Q Et voici le code pour creacuteer nossix eacuteleacutements du menu

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau G_CALLBACK (cb_new) user_data) menu_item_new (GTK_MENU (p_menu) _Ouvrir G_CALLBACK (cb_open) user_data) menu_item_new (GTK_MENU (p_menu) _Enregistrer G_CALLBACK (cb_save) user_data) menu_item_new (GTK_MENU (p_menu) Enregistrer _sous G_CALLBACK (cb_saveas) user_data) menu_item_new (GTK_MENU (p_menu) _Fermer G_CALLBACK (cb_close) user_data) menu_item_new (GTK_MENU (p_menu) _Quitter G_CALLBACK (cb_quit) user_data)

Voilagrave notre menu est creacuteeacute il nous reste plus quagrave linteacutegrer agrave notre fenecirctre

mainc gtk_box_pack_start (GTK_BOX (p_main_box) GTK_WIDGET (menu_new (p_text_view)) FALSE FALSE 0)

Le problegraveme cest que nous avons besoin de passer le GtkTextView lors de la creacuteation du menu (qui est utiliseacute par lesfonctions cb_new et cb_open) or celui-ci est creacuteeacute apregraves le menu (puisque nous creacuteons les widgets dans lordre ougrave ilfaut les inteacutegrer agrave linterface (8) ) nous devons creacuteer le GtkTextView (seul lappel agrave gtk_text_view_new est deacuteplaceacute)

XII-C - Code source

chapitre12zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 36 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIII - Les barres doutils

XIII-A - Aperccedilu

Cliquez pour agrandir

XIII-B - Creacuteation dune barre doutils

La creacuteation dune barre doutils ressemble fort agrave celle dun menu en plus simple puisquil ny a pas de sous menu on creacutee notre barre doutils (gtk_toolbar_new) puis les eacuteleacutements de la barre pour cela on utilise des boutons(gtk_tool_button_new_from_stock) que lon inseacutere dans la barre (gtk_toolbar_insert) Pas conseacutequent notre fichierbarreoutilsc ressemble agrave menuc

barreoutilscinclude ltgtkgtkhgtinclude callbackhinclude barreoutilsh

static void toolbar_item_new (GtkToolbar const gchar GCallback gpointer)

GtkToolbar toolbar_new (gpointer user_data) GtkWidget p_toolbar = NULL

p_toolbar = gtk_toolbar_new () toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_NEW G_CALLBACK (cb_new) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_OPEN G_CALLBACK (cb_open) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE G_CALLBACK (cb_save) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE_AS G_CALLBACK (cb_saveas) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_CLOSE G_CALLBACK (cb_close) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_QUIT G_CALLBACK (cb_quit) user_data) return GTK_TOOLBAR (p_toolbar)

static void toolbar_item_new (GtkToolbar p_toolbar const gchar stock_id GCallback callback gpointer user_data) GtkToolItem p_tool_item = NULL

p_tool_item = gtk_tool_button_new_from_stock (stock_id) g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data) gtk_toolbar_insert (p_toolbar p_tool_item -1)

Le code nest pas complet car lorsque jexeacutecute le programme GTK+ affiche en plus des icocircnes le texte sous lesboutons Pour modifier cela il suffit dajouter une ligne de code

barreoutilsc gtk_toolbar_set_style (GTK_TOOLBAR (p_toolbar) GTK_TOOLBAR_ICONS)

Pourquoi gtk_tool_button_new_from_stock retourne un GtkToolItem et non un GtkWidgetcomme nous avons eacuteteacute habitueacute jusquagrave preacutesent Il sagit dune bizarrerie de GTK+ dontje ne connais pas la raison

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 37 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour anticiper un changement dinterface (dans GTK+ 30 peut ecirctre ) nous aurions pueacutecrire

Gtkwidget p_tool_item = NULL

p_tool_item = GTK_WIDGET (gtk_tool_button_new_from_stock (stock_id))g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data)gtk_toolbar_insert (p_toolbar GTK_TOOL_ITEM (p_tool_item) -1)

XIII-C - Code source

chapitre13zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 38 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIV - Les racourcis clavier

XIV-A - Aperccedilu

Cliquez pour agrandir

XIV-B - Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mneacutemoniques ces derniers permettent dacceacuteder agrave un eacuteleacutementseacutequentiellement alors que les raccourcis appellent une fonction si lutilisateur appuie simultaneacutement sur une ouplusieurs touches (geacuteneacuteralement de la forme ltModificateurgtTouche ougrave Modificateur repreacutesente les touches ShiftAlt et Control) Ce raccourci peut ecirctre attacheacute agrave un eacuteleacutement du menu mais ceci nest pas obligatoire

Les raccourcis sont regroupeacutes en groupe dans un GtkAccelGroup quil faut commencer par creacuteer

raccourciscinclude ltgtkgtkhgtinclude callbackhinclude raccourcish

GtkAccelGroup accel_group_new (gpointer user_data) GtkAccelGroup p_accel_group = NULL

p_accel_group = gtk_accel_group_new () return p_accel_group

Vous commencez agrave avoir lhabitude de cette organisation nous allons donc creacuteer une fonction qui va se chargerdajouter un raccourci au groupe

raccourciscstatic void accelerator_new (GtkAccelGroup p_accel_group const gchar accelerator const gchar accel_path GCallback callback gpointer user_data) guint key GdkModifierType mods GClosure closure = NULL

gtk_accelerator_parse (accelerator ampkey ampmods) closure = g_cclosure_new (callback user_data NULL) gtk_accel_group_connect (p_accel_group key mods GTK_ACCEL_VISIBLE closure) gtk_accel_map_add_entry (accel_path key mods)

La fonction gtk_accelerator_parse permet de deacutecomposer une chaicircne de caractegraveres de la forme ltControlgtF1 ouencore ltAltgtA en numeacutero de touche et modificateur

En plus des touches pour creacuteer un raccourci clavier nous avons besoin dune fonction agrave appeler lorsque lutilisateurappuie sur les touches speacutecifieacutees gtk_accel_group_connect attend une fonction du type GClosure regardons ladocumentation de gobject pour savoir agrave quoi cela correspond

typedef struct

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 6 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Tous les codes de ce tutoriel ont eacuteteacute testeacutes sous Linux Debian et Windows XP avecCodeBlocks

I-E - La philosophie GTK+

Voici quelques choix qui ont eacuteteacute faits par leacutequipe de deacuteveloppement de GTK+

bull Les noms de fonctions sont de la forme gtk_type_du_widget_action ceci rend les noms des fonctions tregravesexplicites en contre partie ils peuvent ecirctre tregraves longs

bull Tous les objets manipuleacutes sont des GtkWidget pour que GTK+ veacuterifie quil sagit du bon type dobjet lors delappel agrave une fonction chaque type de widget possegravede une macro de la forme GTK_TYPE_DU_WIDGET agraveutiliser pour transtyper vos widgets

bull La gestion des eacuteveacutenements qui modifient le comportement de lapplication (clique de souris pression dunetouche du clavier) se fait gracircce agrave lutilisation de fonctions de rappel (callback) Pour cela on connecte leswidgets agrave des fonctions qui seront appeleacutees lorsque leacuteveacutenement survient

I-F - Quelques notions de POO

La POO ou Programmation Orienteacutee Objet est un mode de programmation baseacutee sur des objets GTK+ utilisant ceprincipe (2) je vais vous en expliquer les principes de bases

Plutocirct que le deacuteroulement du programme soit reacutegie par une suite dinstruction en POO il est reacutegi par la creacuteationlinteraction et la destruction dobjets en reacutesumeacute la vie des objets qui le composent Un objets est une entiteacute (leparallegravele avec la vie courante est simple un objet pourrait ecirctre un ordinateur) en C on pourrait se repreacutesenter unobjet comme une structure de donneacutees

Un objet est composeacute de proprieacuteteacutes (ce qui correspond agrave nos variables) et de meacutethodes (des fonctions) Pour creacuteerun objet on fait appel agrave son constructeur il sagit dune fonction qui a pour but de creacuteer et dinitialiser lobjet A la finde sa vie lobjet doit ecirctre deacutetruit cest le but du destructeur

Dans la vie courante on peut creacuteer des objets complexes agrave partir de briques de base il est possible de creacuteer denouveaux objets en se basant sur un ou plusieurs objets ce meacutecanisme est appeler heacuteritage (on parle dheacuteritagemultiple lorsquil met en jeu plusieurs objets parents) Lobjet ainsi obtenu heacuterite des proprieacuteteacutes et des meacutethodes deses parents tout en pouvant modifier leur comportement et creacuteer ses propres proprieacuteteacutes et meacutethodes

Lorsque lon souhaite creacuteer un patron pour de futures classes plutocirct que de creacuteer une classe de base qui ne serajamais instancieacutee il est possible de creacuteer une interface

Le dernier concept de POO qui va nous servir dans ce tutoriel est le polymorphisme Ceci permet agrave un objet (prenonspar exemple camion) de se comporter comme lun de ses parents (dans le cas du camion il peut ecirctre vu comme unveacutehicule au mecircme titre quune voiture) Ceci est aussi valable pour des classes impleacutementant la mecircme interface

Pour vous initier aux joies de la programmation orienteacutee objet en C je vous conseille le tutoriel de CGI POO en C

I-G - Notre premier programme

Un programme qui utilise GTK+ est un programme eacutecrit en C avant tout il contient donc le code de base de toutprogramme C

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 7 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

maincinclude ltstdlibhgt

int main (int argc char argv) return EXIT_SUCCESS

Pour pouvoir utiliser les fonctions de GTK+ il faut bien sucircr inclure le fichier den-tecircte correspondant

include ltgtkgtkhgt

La premiegravere chose agrave faire est dinitialiser la machinerie GTK+ gracircce agrave la fonction gtk_init

void gtk_init (int argc char argv)

Cette fonction reccediloit les arguments passeacutes en ligne de commande ceux qui sont speacutecifiques agrave GTK+ sont ensuiteretireacutes de la liste dougrave lutilisation des pointeurs

Ensuite il nous faut creacuteer tous les widgets dont nous avons besoin si neacutecessaire modifier leurs paramegravetres pardeacutefaut les connecter agrave des fonctions callback et ensuite demander leur affichage (tout ceci sera expliciteacute dans lasuite du tutoriel) Une fois la fenecirctre principale creacuteeacutee il suffit de lancer la boucle principale de GTK+

void gtk_main (void)

Cette fonction est une boucle sans fin (seule la fonction gtk_main_quit permet den sortir) qui se charge de geacuterer ledeacuteroulement de notre programme (affichage des widgets envoi de signaux)

Voici donc notre premier programme en CGTK+ qui ne fait rien

maincinclude ltstdlibhgtinclude ltgtkgtkhgt

int main (int argc char argv) Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application

Lancement de la boucle principale gtk_main() return EXIT_SUCCESS

En plus de ne rien faire notre programme ne peut ecirctre termineacute que de faccedilon brutale (Ctrl+C) puisque nous nappelonspas la fonction gtk_main_quit

I-H - Code source

chapitre1zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 8 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

II - Notre premiegravere fenecirctre

II-A - Aperccedilu

II-B - Creacuteation

La fenecirctre principale est repreacutesenteacutee par la classe GtkWindow

La creacuteation dune fenecirctre se fait simplement en appelant le constructeur de cette classe la fonction gtk_window_new

GtkWidget gtk_window_new (GtkWindowType type)

Le seul paramegravetre de cette fonction est le type de fenecirctre souhaiteacute Il ny a que deux possibiliteacutes

bull GTK_WINDOW_TOPLEVEL une fenecirctre classique (cest la base de notre application)

bull GTK_WINDOW_POPUP il sagit dune fenecirctre avec seulement lespace de travail (pas de bordure ni demenu systegraveme)

Cette fonction renvoie un pointeur sur une structure de type GtkWindow (transformer en GtkWidget gracircce aupolymorphisme) qui est lentiteacute qui va nous servir agrave manipuler notre fenecirctre

II-C - Affichage

Si vous essayez deacutecrire un code maintenant vous ne verrez rien pourquoi Tout simplement parce quil faut preacuteciseragrave GTK+ quil faut rendre notre fenecirctre visible gracircce agrave la fonction gtk_widget_show

void gtk_widget_show (GtkWidget widget)

Voici le code qui permet dafficher notre premiegravere fenecirctre

maincinclude ltstdlibhgtinclude ltgtkgtkhgt

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL)

Affichage de la fenetre principale gtk_widget_show (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 9 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Ceux qui se sont essayeacutes agrave la creacuteation dapplications graphiques avec lAPI Windows comprendront la simpliciteacutede ce code

II-D - Destruction

Dans lexemple preacuteceacutedent si vous avez essayeacute de terminer lapplication en fermant la fenecirctre (Alt+F4 ou en cliquantsur la petite croix) vous vous ecirctes peut-ecirctre aperccedilu que lapplication tournait encore en fond cest le mecircme problegravemeque pour le chapitre preacuteceacutedent on ne fait pas appel agrave gtk_main_quit Mais comment appeler cette fonction puisquequune fois gtk_main appeleacutee nous ne pouvons rien faire Cest lagrave quintervient le meacutecanisme des callback A chaqueeacuteveacutenement qui se produit la bibliothegraveque GObject produit un signal si nous souhaitons modifier le comportementpar deacutefaut du signal il suffit de connecter notre fonction callback agrave leacuteveacutenement souhaiteacute

define g_signal_connect(instance detailed_signal c_handler data)

Cette macro permet dintercepter leacuteveacutenement detailed_signal de lobjet instance gracircce agrave la fonction c_handler quidoit ecirctre du type GCallback

void (GCallback) (void)

Les fonctions callback peuvent bien sucircr recevoir des paramegravetres mais leur nature et leur nombre deacutependent ducontexte tout est geacutereacute par la bibliothegraveque GObject Le prototype le plus courant pour une fonction de rappel estle suivant

void callback (GtkWidget p_widget gpointer user_data)

Dont le premier paramegravetre est le widget qui a reccedilu le signal et le second correspond au paramegravetre data de la fonctiong_signal_connect qui nous permet de passer des informations aux fonctions callback Pour finir proprement notreapplication il suffit dintercepter le signal destroy de notre fenecirctre et dy assigner la fonction gtk_main_quit qui neprend pas dargument Voici donc notre premiegravere application fonctionnelle

maincinclude ltstdlibhgtinclude ltgtkgtkhgt

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (gtk_main_quit) NULL)

Affichage de la fenetre principale gtk_widget_show (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

Il est plus courant de creacuteer notre propre fonction de rappel pour quitter le programme ceci permet de libeacuterer lameacutemoire alloueacutee fermer les fichiers ouverts

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 10 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

maincinclude ltstdlibhgtinclude ltgtkgtkhgt

void cb_quit (GtkWidget gpointer)

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (cb_quit) NULL)

Affichage de la fenetre principale gtk_widget_show (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

void cb_quit (GtkWidget p_widget gpointer user_data) gtk_main_quit()

Parametres inutilises (void)p_widget (void)user_data

Le preacutefixe cb_ permet de diffeacuterencier les fonctions callback quil est preacutefeacuterable de regrouper dans un ou plusieursfichiers seacutepareacutes

A la fin de la fonction je transtype les paramegravetres inutiliseacutes pour eacuteviter que moncompilateur mindique des variables non utiliseacutees cest le problegraveme avec les fonctionscallback lAPI nous impose un prototype

II-E - Code source

chapitre2zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 11 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

III - Fermer notre fenecirctre gracircce aux boutons

III-A - Aperccedilu

III-B - Les boutons poussoir

Maintenant que notre programme se termine proprement il est plus convivial de proposer agrave lutilisateur un boutonpour quitter Pour creacuteer un bouton poussoir il existe plusieurs possibiliteacutes

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 premiegravere fonction creacutee un bouton qui peut servir pour contenir nimporte quel autre widget (label image) Si voussouhaitez creacuteer un bouton avec du texte dessus utilisez directement la seconde fonction qui prend en argument letexte agrave afficher Si vous souhaitez ajouter un raccourci clavier (accessible avec la touche Alt) la troisiegraveme fonctionpermet den speacutecifier un en faisant preacuteceacuteder une lettre (geacuteneacuteralement la premiegravere) dun underscore _ (si voussouhaitez afficher le caractegravere _ il faut en mettre deux) Enfin la derniegravere fonction permet dutiliser les Stock Itemsqui sont un ensemble deacuteleacutements preacutedeacutefinis par GTK+ pour les menus et barres doutils Le seul paramegravetre de cettefonction est le nom de leacuteleacutement et GTK+ se charge dafficher licocircne approprieacutee ainsi que le texte suivant la languechoisie et un raccourci

Cest bien sucircr cette derniegravere fonction que nous allons utiliser et ce le plus souvent possible Voici le code pour creacuteerun tel bouton

maincGtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_QUIT)

Pour obtenir tous les types de stocks items disponibles GtkStockItem

Bien sucircr comme pour la fenecirctre si lon veut voir quelque chose il faut demander agrave GTK+ dafficher notre widget

maincgtk_widget_show (p_button)

Mais pas seulement En effet il faut preacuteciser agrave GTK+ ougrave doit ecirctre afficheacute notre bouton Pour cela la classe GtkWindowest deacuteriveacutee de la classe GtkContainer qui est comme son nom le laisse penser un conteneur pour widget Pourajouter un widget il suffit de faire appel agrave la fonction gtk_container_add

void gtk_container_add (GtkContainer container GtkWidget widget)

Le premier paramegravetre de cette fonction est un GtkContainer or nous souhaitons passer notre fenecirctre qui est unGtkWidget pour ne pas avoir de problegravemes il faut utiliser le systegraveme de macro offert par GTK+ pour transtyper notreGtkWidget en GtkContainer (eh oui en C le polymorphisme a ses limites)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 12 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

maincgtk_container_add (GTK_CONTAINER (p_window) p_button)

Ce meacutecanisme de transtypage permet agrave GTK+ de veacuterifier que notre GtkWidget est bien compatible avec lutilisationque lon souhaite en faire En cas deacutechec GTK+ nous preacutevient en affichant un message dans la console

(gtk_boutonexe1044) Gtk-CRITICAL gtk_container_add assertion `GTK_IS_CONTAINER (container) failed

Pour finir il faut connecter notre bouton pour appeler notre fonction cb_quit lorsque lutilisateur clic dessus (ce quicorrespond agrave leacuteveacutenement clicked)

g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_quit) NULL)

Pour eacuteviter dappeler la fonction gtk_widget_show pour tous les widgets de notreapplication on peut se contenter dun seul appel agrave la fonction gtk_widget_show_all quipermet dafficher tous les widgets contenus dans celui passeacute agrave la fonction

maincinclude ltstdlibhgtinclude ltgtkgtkhgtinclude callbackh

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (cb_quit) NULL)

GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_QUIT) gtk_container_add (GTK_CONTAINER (p_window) p_button) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_quit) NULL)

Affichage de la fenetre principale gtk_widget_show_all (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

III-C - Code source

chapitre3zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 13 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IV - Comment afficher plusieurs widgets

IV-A - Aperccedilu

IV-B - Le problegraveme

Dans la partie preacuteceacutedente nous avons reacuteussi agrave afficher un bouton dans la fenecirctre de notre application Si vous avezessayeacute dajouter un second widget GTK+ agrave ducirc vous reacutepondre poliment

(gtk_boxexe492) Gtk-WARNING Attempting to add a widget with typeGtkButton to a GtkWindow but as a GtkBin subclass a GtkWindow can only containone widget at a time it already contains a widget of type GtkButton

Les plus anglophiles dentre vous auront compris que GTK+ naccepte pas lajout un second widget dans notre fenecirctretout simplement parce quil y en a deacutejagrave un et que la sous classe GtkBin (classe megravere de notre GtkWindow) ne peutcontenir quun seul widget

IV-C - La solutions

Pour contourner ce problegraveme il faut commencer par creacuteer un widget qui accepte den contenir plusieurs autrespour ensuite y ajouter tout ce dont nous avons besoin Pour linstant nous utiliserons quun seul widget (il existetrois classes qui permettent ceci) il sagit des GtkBox Il sagit de la meacutethode que jutilise le plus souvent Ce nestpeut-ecirctre pas la plus simple agrave maicirctriser mais elle extrecircmement souple et puissante Elle consiste agrave creacuteer une boicirctepuis agrave y ajouter les widgets les uns apregraves les autres (soit au deacutebut soit agrave la fin) Il existe deux classes heacuteritant deGtkBox les GtkVBox qui empilent les widgets dans le sens vertical et les GtkHBox qui font de mecircme mais dansle sens horizontal Les fonctions pour manipuler ces deux classes sont les mecircmes seule la fonction pour les creacuteerportent un nom diffeacuterent

GtkWidget gtk_vbox_new (gboolean homogeneous gint spacing)GtkWidget gtk_hbox_new (gboolean homogeneous gint spacing)

Le paramegravetre homogeneous permet de reacuteserver pour chaque widget une zone de taille identique (zone que le widgetnest pas obligeacute de remplir) et spacing permet dajouter une bordure en pixels (espacement autour de la GtkBox)Ensuite il suffit dajouter les diffeacuterents widgets gracircce aux fonctions

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)

Qui ajoutent reacuteciproquement le widget child au deacutebut et agrave la fin de box Le paramegravetre expand permet au widget davoirle plus de place possible (si le paramegravetre homogeneous vaut TRUE cette option a aucun effet) Si plusieurs widgetont ce paramegravetre agrave TRUE ils se partagent de faccedilon eacutegale lespace Loption fill permet au widget de remplir toutlespace qui lui ait reacuteserveacute

Pour reacuteellement comprendre linfluence de ces paramegravetres il faut faire des tests en modifiant un agrave un chaqueparamegravetre et observer les effets dun redimentionnement de la fenecirctre principale

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 14 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Le plus gecircnant avec cette meacutethode cest quil faut jongler entre les GtkHBox et les GtkVBox en les imbriquant pourobtenir le reacutesultat souhaiter nheacutesitez pas agrave utiliser une feuille et un crayon )

Pour en revenir agrave notre eacutediteur de texte nous allons preacuteparer notre application agrave contenir les futurs widgetsNous utilisons un GtkVBox pour lensemble des widgets (il sagit de la boicircte principale qui pourra contenir dautresGtkContainer selon nos besoins)

maincinclude ltstdlibhgtinclude ltgtkgtkhgtinclude callbackh

int main (int argc char argv) GtkWidget p_window = NULL GtkWidget p_main_box = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (cb_quit) NULL)

Creation du conteneur principal p_main_box = gtk_vbox_new (FALSE 0) gtk_container_add (GTK_CONTAINER (p_window) p_main_box)

Creation du bouton Quitter GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_QUIT) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_quit) NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_button FALSE FALSE 0)

Affichage de la fenetre principale gtk_widget_show_all (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

IV-D - Code source

chapitre4zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 15 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

V - Afficher le contenue dun fichier

V-A - Aperccedilu

Cliquez pour agrandir

V-B - Saisir du texte

Les choses seacuterieuses vont commencer il sagit de mettre en place le widget qui va nous permettre dafficher etdeacutediter du texte Il sagit de la classe GtkTextView Gracircce agrave GTK+ la mise en place est toujours aussi simple

mainc GtkWidget p_text_view = NULL Creation de la zone de texte p_text_view = gtk_text_view_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_text_view TRUE TRUE 0)

Comme il sagit de la partie centrale de notre application nous demandons agrave ce quelle prenne le plus de placepossible (gracircce agrave la fonction gtk_box_pack_start)

Puisque nous voulons afficher les boutons en dessous de la zone de texte il faut ajouter ce morceau de code avantcelui creacuteant le bouton

V-C - Ouvrir un fichier

Maintenant nous avons une belle zone de texte il faut la remplir avec le contenu dun fichier Pour ce faire nousallons commencer par ajouter un bouton ouvrir

mainc Creation du bouton Ouvrir GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_OPEN) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_open) p_text_view) gtk_box_pack_start (GTK_BOX (p_main_box) p_button FALSE FALSE 0)

Si vous exeacutecutez le programme maintenant (3) vous remarquerez que les boutons sont ajouteacutes les uns en dessousdes autres ce qui diminue la zone de saisie (avec deux boutons ce nest pas gecircnant mais au bout dune dizaineccedila risque decirctre probleacutematique) Pour pallier ce problegraveme nous allons utiliser un nouveau style de GtkBox lesGtkButtonBox qui sont preacutevus pour contenir des boutons (ccedila tombe plutocirct bien D) Donc pour eacuteviter de diminuerla zone de saisie et comme nous avons de la place en largueur nous allons utiliser un GtkHButtonBox qui va ecirctreinclus dans la p_main_box Voici les modifications agrave effectuer

mainc GtkWidget p_button_box = NULL Creation du conteneur pour les boutons p_button_box = gtk_hbutton_box_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_button_box FALSE FALSE 0)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 16 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc gtk_box_pack_start (GTK_BOX (p_button_box) p_button FALSE FALSE 0) gtk_box_pack_start (GTK_BOX (p_button_box) p_button FALSE FALSE 0)

Maintenant il nous reste plus quagrave creacuteer la fonction cb_open dans le fichier callbackc pour linstant nous nouscontenterons douvrir toujours le mecircme fichier nous verrons plus tard comment laisser le choix agrave lutilisateur

callbackcdefine DEFAULT_FILE mainc

void cb_open (GtkWidget p_widget gpointer user_data) open_file (DEFAULT_FILE GTK_TEXT_VIEW (user_data))

Parametre inutilise (void)p_widget

Vous aurez compris que lon va deacuteleacuteguer tout le travail agrave la fonction open_file qui devra ouvrir le fichier dont le nomest passeacute en premier paramegravetre pour lafficher dans le GktTextView

Jai fait ce choix pour deux raisons le code dune fonction callback peut ecirctre tregraves conseacutequent (surtout si lon souhaitequelle affiche une boicircte de dialogue) et aussi parce que cb_open nest peut ecirctre pas la seule fonction agrave copierun fichier dans un GtkTextView (par exemple lors de la creacuteation dun nouveau fichier lon peut vouloir copier unsquelette de fichier)

Pour copier notre fichier plutocirct que dutiliser la fonction fgets nous allons nous servir de la glib (4) qui proposela fonction

gboolean g_file_get_contents (const gchar filename gchar contents gsize length GError error)

Qui nous renvoit le contenu du fichier nommeacute filename dans le tampon contents Il est possible de reacutecupeacuterer lenombre de caractegraveres copieacutes et retourne TRUE en cas de succegraves sinon FALSE et dans ce cas une structure de typeGError est creacutee pour en savoir plus sur le type derreur rencontreacute

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView else print_warning (Impossible douvrir le fichier sn file_name)

Je pense quun certain nombre dexplications simpose (surtout si je vais trop vite nheacutesitez pas agrave marrecircter )

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 17 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

bull g_return_if_fail est une macro qui peut ecirctre compareacutee agrave assert sauf quelle se contente de sortir de la fonctionsi lexpression passeacutee en paramegravetre est fausse Cest une meacutethode pratique pour veacuterifier la validiteacute desparamegravetres (si la fonction doit retourne une valeur utiliseacute plutocirct g_return_val_if_fail qui prend un secondparamegravetre la valeur agrave retourner)

bull Ensuite on essaie de reacutecupeacuterer le contenu de notre fichier

bull Si cela eacutechoue nous le signalons agrave lutilisateur agrave laide de la fonction print_warning

bull Le type gchar est une redeacutefinition du type char par la glib (il en va de mecircme pour tous les autres types du C)privileacutegiez ces types lorsque vous utilisez des fonctions de cette bibliothegraveques

Mais quest-ce donc cette fonction print_warning Cest une fonction que nous allons creacuteer semblable agrave printf quisignalera agrave lutilisateur quune erreur non critique est survenue Comme nous navons pas encore abordeacute les boicirctesde dialogue pour afficher un message il sagira pour linstant dune simple redeacutefinition de printf Pendant que noussommes dans laffichage des messages nous allons aussi creacuteer deux fonctions print_info et print_error qui vontrespectivement afficher un message dinformation et un message derreur critique (ce qui entraicircne la terminaison duprogramme) tout ceci dans un nouveau fichier errorc

errorhifndef H_ERRORdefine H_ERROR

void print_info (char )void print_warning (char )void print_error (char )

endif not H_ERROR

errorcinclude ltstdarghgtinclude ltstdiohgtinclude ltstdlibhgtinclude errorh

void print_info (char format ) va_list va

va_start (va format) printf (Information ) vprintf (format va) printf (n)

void print_warning (char format ) va_list va

va_start (va format) fprintf (stderr Erreur ) vfprintf (stderr format va) fprintf (stderr n)

void print_error (char format ) va_list va

va_start (va format) fprintf (stderr Erreur fatale ) vfprintf (stderr format va) fprintf (stderr n) exit (EXIT_FAILURE)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 18 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

Pour en finir avec louverture dun fichier il nous reste agrave copier contents dans le GtkTextView En fait le GtkTextViewne gegravere que la forme pour modifier le contenu il faut passer par les GtkTextBuffer Commenccedilons donc par reacutecupeacutererce fameux GtkTextBuffer

callbackc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (p_text_view)

Et pour finir on utilise la fonction

void gtk_text_buffer_insert (GtkTextBuffer buffer GtkTextIter iter const gchar text gint len)

Reacutecapitulons buffer est le GtkTextBuffer que lon vient de reacutecupeacuterer text cest le texte agrave afficher et len la taille dece dernier (ou -1 sil sagit dune chaicircne de caractegraveres au sens du langage C)

Mais quest-ce donc ce GtkTextIter On peut voir cela comme un curseur virtuel qui indique la position agrave laquelleeffectuer linsertion de texte dans le GtkTextBuffer (5) Allons voir ce que la documentation peut nous apprendreagrave leur sujet (6)

typedef struct GtkTextIter is an opaque datatype ignore all these fields Initialize the iter with gtk_text_buffer_get_iter_ functions GtkTextIter

Voilagrave on a notre solution suffit de rechercher les fonctions commenccedilant par gtk_text_buffer_get_iter_ voici la liste

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)

La fonction gtk_text_buffer_get_iter_at_line fait parfaitement laffaire

callbackc GtkTextIter iter

gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1)

Cependant si vous ne voulez pas avoir de problegravemes avec le codage des caractegraveres il vaut mieux convertir le codagelocal vers utf8 Voici le reacutesultat final

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 19 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gchar utf8 = NULL GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_text_buffer_insert (p_text_buffer ampiter utf8 -1) g_free (utf8) utf8 = NULL

V-D - La petite touche finale

Pour finir cette laborieuse partie sur une petite touche estheacutetique nous allons demander agrave GTK+ de nous lancerlapplication en plein eacutecran Pour se faire il suffit dajouter lors de la creacuteation de la fenecirctre principale

maincgtk_window_maximize (GTK_WINDOW (p_window))

On peut mecircme se permettre une pointe dexcentriciteacute en modifiant le titre de notre fenecirctre

maincgtk_window_set_title (GTK_WINDOW (p_window) Editeur de texte en GTK+)

V-E - Code source

chapitre5zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 20 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VI - Choisir un fichier

VI-A - Aperccedilu

Cliquez pour agrandir

VI-B - Utilisation dun GtkFileChooserFile

Jusquagrave preacutesent lutilisateur navait pas le choix quant au fichier agrave ouvrir heureusement GTK+ vient agrave notre aide gracircceau widget GtkFileChooserFile qui est tout simplement une boicircte de dialogue qui propose agrave lutilisateur de seacutelectionnerun fichier dans son arborescence disque

Commenccedilons par creacuteer notre boicircte de dialogue dans la fonction cb_open

callbackcvoid cb_open (GtkWidget p_widget gpointer user_data) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Ouvrir un fichier NULL GTK_FILE_CHOOSER_ACTION_OPEN GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_OPEN GTK_RESPONSE_ACCEPT NULL)

Cette fonction neacutecessite le titre de la boicircte de dialogue une fenecirctre parente le type daction (ici on souhaite ouvrir unfichier GTK+ autorisera lutilisateur agrave seacutelectionner uniquement les fichiers existants) Pour finir il sagit dun couple devaleurs GTK_STOCK_ITEMGTK_STOCK_RESPONSE qui permet de creacuteer un bouton utilisant le stock ID speacutecifieacuteet lorsque celui-ci est cliqueacute la fonction servant agrave lancer la boicircte de dialogue retournera le reacuteponse ID correspondantIl existe une seacuterie de valeurs deacutefinies par GTK+ quil est conseilleacute dutiliser

typedef enum GTK returns this if a response widget has no response_id or if the dialog gets programmatically hidden or destroyed GTK_RESPONSE_NONE = -1

GTK wont return these unless you pass them in as the response for an action widget They are for your convenience GTK_RESPONSE_REJECT = -2 GTK_RESPONSE_ACCEPT = -3

If the dialog is deleted GTK_RESPONSE_DELETE_EVENT = -4

These are returned from GTK dialogs and you can also use them yourself if you like GTK_RESPONSE_OK = -5 GTK_RESPONSE_CANCEL = -6 GTK_RESPONSE_CLOSE = -7 GTK_RESPONSE_YES = -8

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 21 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GTK_RESPONSE_NO = -9 GTK_RESPONSE_APPLY = -10 GTK_RESPONSE_HELP = -11 GtkResponseType

Nous indiquons la fin des couples stock idreacuteponse id avec la valeur NULL

Une fois la boicircte de dialogue creacuteee on demande agrave GTK+ de lafficher gracircce agrave la fonction gtk_dialog_run puis onreacutecupegravere sa valeur de retour qui correspond au bouton cliqueacute par lutilisateur

callbackc if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

Ici ce qui nous inteacuteresse cest lorsque que lutilisateur clique sur le bouton ouvrir (donc gtk_dialog_run renvoieGTK_RESPONSE_ACCEPT) dans ce cas il nous suffit de reacutecupeacuterer le nom du fichier seacutelectionneacute puis de louvrir

callbackc gchar file_name = NULL

file_name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) open_file (file_name GTK_TEXT_VIEW (user_data)) g_free (file_name) file_name = NULL

Pour finir dans tous les cas on noublie pas de deacutetruire la boicircte de dialogue

callbackc gtk_widget_destroy (p_dialog)

Et voilagrave le travail lutilisateur peut ouvrir le fichier quil souhaite

VI-C - Code source

chapitre6zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 22 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VII - Interlude

Avant daller plus loin dans lameacutelioration de linterface de notre eacutediteur il est neacutecessaire de modifier sonfonctionnement interne (ne vous inquieacutetez je nai pas dit chambouler) en effet souvenez-vous dans lintroduction jaieacutevoqueacute la possibiliteacutes douvrir plusieurs documents gracircce agrave un systegraveme donglets Pour cela il faut sauvegarder lesproprieacuteteacutes de chaque document ouvert Pris agrave temps ce genre de modification nest pas trop lourde mais si nousattendons cela risque de devenir un vrai casse tecircte

Pour cela nous allons utiliser une structure de donneacutee pour chaque document ouvert qui devra garder en meacutemoirele chemin complet du fichier (ou NULL si le document nest pas encore sauvegarder) sil agrave eacutetait modifier depuis laderniegravere sauvegarde et le GtkTextView qui sert agrave son affichage Voici donc la structure qui va nous servir

documenthtypedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

Sachant que nous serons ameneacute agrave stocker plusieurs occurrences de cette structure il serait bon de reacutefleacutechir degravesmaintenant agrave la structure de donneacutee agrave utiliser pour les stocker La premiegravere ideacutee qui vient agrave lesprit est un tableaualloueacute dynamiquement cependant lutilisateur peut souhaiter fermer un document qui se trouve au milieu on estalors obligeacute de deacutecaler toutes les cellules en amont Dans ce cas il parait naturel dutiliser une liste chaicircneacutee Parchance la glib propose une bibliothegraveque de gestion des listes chaicircneacutees cela nous fera gagner du temps le momentvenu Pour linstant on se contente de creacuteer une structure de donneacutees qui contiendra tous les documents ouverts(stockeacutee dans une GList) et un pointeur sur le document actif (actuellement comme nous navons quun documentouvert en mecircme temps on manipulera uniquement ce pointeur)

documenthtypedef struct GList tous document_t actif docs_t

Maintenant se pose le problegraveme de savoir comment transmettre cette structure On pourrait se servir du paramegravetreuser_data preacutesent dans toutes les fonctions callback mais certaines fonctions utilise deacutejagrave ce paramegravetre (la fonctioncb_open par exemple) il faudrait creacuteer un champs suppleacutementaire dans notre structure documents_s Une solutionplus simple est de creacuteer une variable globale agrave lensemble du programme Ceux qui passe reacuteguliegraverement sur le forumC savent que cest fortement deacuteconseilleacute mais ici nous nous trouvons dans lune des rares exceptions agrave la regravegle Detoute faccedilon cela revient au mecircme que de passer ladresse de notre structure agrave toutes les fonctions callback Nousdeacutefinissons donc un nouveau fichier den-tecircte

documenthifndef H_DOCUMENTdefine H_DOCUMENT

include ltgtkgtkhgt

typedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 23 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

documenthtypedef struct GList tous document_t actif docs_t

extern docs_t docs

endif not H_DOCUMENT

Et dans le fichier mainc

maincinclude documenth

docs_t docs = NULL NULL

Pour linstant la seule fonction qui modifie leacutetat dun document est la fonction open_file il faut donc inclure documenthdans callbackc et modifier leacutegegraverement la fonction pour enregistrer le document ouvert

callbackc if (g_file_get_contents (file_name ampcontents NULL NULL)) Pour linstant il faut allouer la memoire par la suite on modifira simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = g_strdup (file_name) Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = p_text_view Le document vient detre ouvert il nest donc pas modifie docsactif-gtsauve = TRUE

Ne soyez pas choqueacute si je ne teste pas le retour de la fonction g_malloc pour veacuterifier quilnest pas NULL En effet cette derniegravere met fin agrave lapplication si lallocation eacutechoue

VII-A - Code source

chapitre7zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 24 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VIII - Sauvegarder les modification

VIII-A - Aperccedilu

Cliquez pour agrandir

VIII-B - Enregistrer

Avant de pouvoir sauvegarder un document il faut quil soit modifieacute Comment savoir que le contenu du fichier a eacuteteacutemodifier Gracircce au signal changed du GtkTextBuffer que nous interceptons gracircce agrave la fonction cb_modifie

mainc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (p_text_view)) g_signal_connect (G_OBJECT (p_text_buffer) changed G_CALLBACK (cb_modifie) NULL)

Cette derniegravere modifie simplement le champ sauve du document

callbackcvoid cb_modifie (GtkWidget p_widget gpointer user_data) if (docsactif) docsactif-gtsauve = FALSE

Pour la sauvegarde il faut distinguer deux cas soit il sagit de la premiegravere sauvegarde du fichier il faut alors demanderle nom du fichier agrave lutilisateur (cela ressemble fortement agrave louverture dun fichier) soit le fichier est deacutejagrave preacutesent surle disque il suffit de remplacer son contenu par celui du GtkTextViewer Nous avons convenu quun fichier qui neacutetaitpas encore enregistreacute avait sa proprieacuteteacute chemin agrave NULL

Bien sucircr cela na lieu que si un fichier est ouvert et quil a eacuteteacute modifieacute depuis sa derniegravere sauvegarde

callbackcvoid cb_save (GtkWidget p_widget gpointer user_data) if (docsactif) if (docsactif-gtsauve) Le fichier na pas encore ete enregistre if (docsactif-gtchemin) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Sauvegarder le fichier NULL GTK_FILE_CHOOSER_ACTION_SAVE GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_SAVE GTK_RESPONSE_ACCEPT NULL) if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 25 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc docsactif-gtchemin = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) gtk_widget_destroy (p_dialog) Soit le fichier a deja ete enregistre soit lutilisateur vient de nous fournir son nouvel enplacement on peut donc lenregistrer if (docsactif-gtchemin) else print_warning (Aucun document ouvert)

Il nous reste plus quagrave reacutecupeacuterer le contenu du GtkTextViewer et le copier dans le fichier chemin sans oublier dereconvertir le texte dans le codage local

callbackc FILE fichier = NULL

fichier = fopen (docsactif-gtchemin w) if (fichier) gchar contents = NULL gchar locale = NULL GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) contents = gtk_text_buffer_get_text (p_text_buffer ampstart ampend FALSE) locale = g_locale_from_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL fprintf (fichier s locale) g_free (locale) locale = NULL fclose (fichier) fichier = NULL docsactif-gtsauve = TRUE else print_warning (Impossible de sauvegarder le fichier s docsactif-gtchemin)

Le dernier paramegravetre de la fonction gtk_text_buffer_get_text est mis agrave FALSE car nous ne voulons pas enregistrerles caractegraveres invisibles preacutesent dans le GtkTextBuffer Ces caractegraveres servent agrave mettre en forme le texte (taillecouleur) nous pourrions creacuteer un nouveau format de fichier pour enregistrer la mise en forme

VIII-C - Enregistrer sous

Pour enregistrer notre document sous un autre nom il suffit de faire croire agrave cb_save que le document na pas encoreeacutetait enregistreacute tout simplement en changeant chemin agrave NULL et sauve agrave FALSE

callbackcvoid cb_saveas (GtkWidget p_widget gpointer user_data)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 26 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (docsactif) document_t tmp = docsactif

docsactif-gtchemin = NULL docsactif-gtsauve = FALSE cb_save (p_widget user_data) if (docsactif-gtsauve) (docsactif) = tmp else print_warning (Aucun document ouvert)

Il ne faut pas oublier que lutilisateur peut annuler lenregistrement de ce fait nous sauvegardons leacutetat du documentet si la sauvegarde na pas eu lieu on le restaure

VIII-D - Code source

chapitre8zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 27 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IX - Creacuteer un nouveau document

IX-A - Aperccedilu

Cliquez pour agrandir

IX-B - Nouveau fichier

Maintenant que lutilisateur peut ouvrir et fermer un fichier il est inteacuteressant de lui donner la possibiliteacute den creacuteerun nouveau Je ne reviens pas sur la creacuteation du bouton (ccedila devrait deacutejagrave ecirctre fait D) passons directement agrave lafonction cb_new

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) Pour linstant il faut allouer la memoire par la suite on modifiera simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = NULL Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = GTK_TEXT_VIEW (user_data) Le document vient detre creer il nest donc pas modifie docsactif-gtsauve = TRUE gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Je ne sais pas vous mais pour ma part jai fait un copiercoller de la fonction open_file Et oui ouvrir un document peutse reacutesumer agrave creacuteer un document vide puis remplir le GtkTextView avec le fichier souhaiteacute On peut donc simplifiernotre fonction open_file ainsi

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

cb_new (NULL p_text_view) gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE) p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1) Nous sommes obliges de remetre sauve a TRUE car linsertion du contenu du fichier dans le GtkTextView a appele cb_modfie docsactif-gtsauve = TRUE else print_warning (Impossible douvrir le fichier sn file_name)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 28 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc

Cest beau la factorisation du code Par contre nous sommes obligeacutes de remettre sauve agrave TRUE car nous avonsmodifieacute le GtkTextBuffer

IX-C - Code source

chapitre9zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 29 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

X - Fermer

X-A - Aperccedilu

Cliquez pour agrandir

X-B - Fermer un fichier

Maintenant que nous allouons de la meacutemoire il faut la libeacuterer agrave un endroit Logiquement cela va ecirctre fait agrave la fermeturedu document en guise dexercice je vous laisse creacuteer le bouton dans notre boicircte agrave bouton

Allez je vous aide le stock id correspondant est GTK_STOCK_CLOSE

Voilagrave maintenant si tout cest bien passeacute vous devriez ecirctre arriveacute dans le fichier callbackc avec quelque choseressemblant agrave

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data)

Lorsque lon ferme un document il faut vider le GtkTextView (avec les onglets on se contentera de le supprimer)pour cela il faut reacutecupeacuterer le deacutebut et la fin du GtkTextBuffer et demander agrave GTK+ de supprimer tout ce qui ce trouveentre les deux iteacuterateurs

callbackc Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) gtk_text_buffer_delete (p_text_buffer ampstart ampend) else print_warning (Aucun document ouvert)

Bien sucircr il ne faut pas oublier de libeacuterer la meacutemoire

callbackc g_free (docsactif-gtchemin) docsactif-gtchemin = NULL docsactif-gtp_text_view = NULL g_free (docsactif) docsactif = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 30 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour symboliser la fermeture dun document nous deacutesactivons le GtkTextView lors de la fermeture (ne pas oublierde le faire aussi dans mainc)

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) FALSE)

Et nous le reacuteactivons lors de louverture si celle si reacuteussie

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Lorsque lutilisateur quitte lapplication il faut bien sucircr fermer le document sil y en a un ouvert

void cb_quit (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data) gtk_main_quit()

Et aussi lorsquil creacuteeacute un nouveau document (et par conseacutequent lorsquil ouvre un fichier puisque lon fait appel agravecb_new)

void cb_new (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data)

X-C - Enregistrer avant de fermer

Si le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde geacuteneacuteralement le programme le signale agrave lutilisateur etlui propose de sauvegarder ou dannuler la fermeture Pour se faire nous devons modifier la fonction cb_close avantde fermer le document nous allons afficher une boicircte de dialogue

Pour creacuteer une boicircte de dialogue simplement il existe la classe GtkDialog et comme nous avons besoin de boutons(pour que lutilisateur fasse son choix) nous allons creacuteer notre boicircte avec la fonction

GtkWidget gtk_dialog_new_with_buttons (const gchar title GtkWindow parent GtkDialogFlags flags const gchar first_button_text )

Nous retrouvons les mecircmes options que pour le GtkFileChooserDialog mis agrave part option du type GtkDialogFlags

typedef enum GTK_DIALOG_MODAL = 1 ltlt 0 appel gtk_window_set_modal (win TRUE) GTK_DIALOG_DESTROY_WITH_PARENT = 1 ltlt 1 appel gtk_window_set_destroy_with_parent () GTK_DIALOG_NO_SEPARATOR = 1 ltlt 2 Pas de barre de separation au dessus des boutons GtkDialogFlags

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 31 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Nous nous contenterons de rendre notre fenecirctre modale (7)

Pour avoir accegraves agrave notre fenecirctre principale nous ajoutons un champs p_main_window agrave notre structure globaledocs_t que nous initialisons dans la fonction main

mainc docsp_main_window = GTK_WINDOW (p_window)

Il nous reste plus qua creacuteer notre boicircte de dialogue avec trois boutons Oui Non Annuler

callbackc if (docsactif-gtsauve) GtkWidget p_dialog = NULL

p_dialog = gtk_dialog_new_with_buttons (Sauvegarder docsp_main_window GTK_DIALOG_MODAL GTK_STOCK_YES GTK_RESPONSE_YES GTK_STOCK_NO GTK_RESPONSE_NO GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL NULL)

Nous obtenons donc une structure de type GtkDialog

typedef struct GtkWidget vbox GtkWidget action_area GtkDialog

Nous remarquons que cette structure contient deux membres qui permettent dacceacuteder agrave une GtkBox ougrave nous allonsajouter le contenu de la fenecirctre et agrave la partie contenant les boutons

Ensuite la construction de la fenecirctre est identique agrave celle de la fenecirctre principale ici nous nous contenterons dajouterun GtkLabel

callbackc GtkWidget p_label = NULL p_label = gtk_label_new (Voulez-vous sauvegarder les modifications ) gtk_box_pack_start (GTK_BOX (GTK_DIALOG (p_dialog)-gtvbox) p_label TRUE TRUE 0)

Une fois notre fenecirctre precircte il suffit de faire appel agrave la fonction gtk_dialog_run qui va afficher notre GtkDialog et nousretourner le reacuteponse id correspondant au bouton cliqueacute par lutilisateur

callbackc switch (gtk_dialog_run (GTK_DIALOG (p_dialog))) case GTK_RESPONSE_YES cb_save (p_widget user_data) break case GTK_RESPONSE_NO break case GTK_RESPONSE_CANCEL gtk_widget_destroy (p_dialog) return break

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 32 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc gtk_widget_destroy (p_dialog)

Si lutilisateur clique sur non on ne fait rien (le document sera simplement fermeacute) sur oui on enregistre avant defermer et pour finir sil annule on quitte la fonction

X-D - Code source

chapitre10zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 33 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XI - Les barres de deacutefilement

XI-A - Aperccedilu

Cliquez pour agrandir

XI-B - Ajouter des barres de deacutefilement

Apregraves le dernier chapitre quelque peu laborieux voici une partie plus simple mais qui va rendre notre applicationplus pratique En effet si vous avez essayeacute douvrir un fichier de grande taille vous avez pu remarquer que pourpouvoir lire la fin du fichier il fallait utiliser les touches du clavier pas tregraves convivial

Pour rendre la navigation plus aiseacutee on utilise des barres de deacutefilement

mainc GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_scrolled_window TRUE TRUE 0)

Creation de la zone de texte gtk_container_add (GTK_CONTAINER (p_scrolled_window) p_text_view)

Le constructeur de notre GtkScrolledWindow prend en argument deux GtkAdjustment qui permettent de deacutefinirdiffeacuterentes proprieacuteteacutes de la barre de deacutefilement (taille dune page la position de deacutepart) nous laissons GTK+ faireen passant NULL

Cest un bon deacutebut mais estheacutetiquement on peut faire mieux mecircme sil nest pas utile davoir une barre de deacutefilementelle est quand mecircme afficheacutee On peut demander agrave GTK+ de les afficher que si cela est neacutecessaire

mainc gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC)

En fait nous avons de la chance car la classe GtkTextView fait partie des widget qui supporte de faccedilon native les barresde deacutefilement Comment le savoir Ce genre de widget possegravede une ou deux proprieacuteteacutes de type GtkAdjustment (unepour la barre verticale lautre pour la barre horizontale) Actuellement seulement trois classes en sont capables lesGtkTextView les GtkTreeView et les GtkLayout

Comment faire pour les autres widgets Il faut passer par une classe adaptateur GtkViewport afin de creacuteer lesGtkAdjustment

XI-C - Code source

chapitre11zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 34 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XII - Les menus

XII-A - Aperccedilu

Cliquez pour agrandir

XII-B - Creacuteation du menu

Pour simplifier nous avons utiliseacute des boutons pour permettre agrave lutilisateur de creacuteer un document ouvrir un fichierMais il est plus courant dutiliser un menu pour afficher ces options GTK+ propose trois maniegraveres de creacuteer un menu

bull GtkItemFactory cette meacutethode est obsolegravete depuis la version 24 de GTK+

bull GtkUIManager cest ce quon appel une usine agrave gaz pour en savoir plus vous pouvez vous reporter aututoriel Utilisation de GtkUIManager

bull GtkMenu cest ce widget que nous allons eacutetudier il permet de creacuteer un menu manuellement (agrave lopposeacute deGtkUIManager)

Un menu selon GTK+ est composeacute de plusieurs eacuteleacutements

bull GtkMenuBar la barre de menu elle-mecircme

bull GtkMenu la partie deacuteroulante qui contient les diffeacuterents eacuteleacutements

bull GtkMenuItem cest sur ce widget que lutilisateur clique pour lancer une action

Pour commencer faisons linventaire de ce que nous avons besoin

bull Un GtkMenuBar qui sert de base au menu

bull Un GtkMenu pour commencer nous nous aurons dun menu Fichier

bull Six GtkMenuItem pour remplacer nos six boutons

Commenccedilons par la creacuteation du menu nous mettons ce code dans un nouveau fichier dont seul la fonction menu_newsera accessible

menucGtkMenuBar menu_new (gpointer user_data) GtkWidget p_menu_bar = NULL

p_menu_bar = gtk_menu_bar_new () return GTK_MENU_BAR (p_menu_bar)

Le paramegravetre user_data nous servira lors de la connexion des callbacks (nous en avons besoin pour les fonctionscb_new et cb_open)

Ensuite nous allons creacuteer notre sous menu Fichier

menuc Menu Fichier

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 35 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

menuc GtkWidget p_menu = NULL GtkWidget p_menu_item = NULL

p_menu = gtk_menu_new () p_menu_item = gtk_menu_item_new_with_mnemonic (_Fichier) gtk_menu_item_set_submenu (GTK_MENU_ITEM (p_menu_item) p_menu) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu_bar) p_menu_item) return GTK_MENU_BAR (p_menu_bar)

Un sous menu est en fait un GtkMenuItem auquel on assigne un GtkMenu Il faut bien sucircr terminer la creacuteation dusous-menu en lajoutant agrave la barre de menu

Pour finir nous creacuteons les eacuteleacutements du menu les GtkItemMenu Il existe plusieurs types deacuteleacutements (comparableaux diffeacuterents types de bouton) pour commencer nous nutiliserons que le type de base Comme cette opeacuteration estreacutepeacutetitive nous allons creacuteer une fonction pour le faire

menucstatic void menu_item_new (GtkMenu p_menu const gchar title GCallback callback gpointer user_data) GtkWidget p_menu_item = NULL

p_menu_item = gtk_menu_item_new_with_mnemonic (title) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu) p_menu_item) g_signal_connect (G_OBJECT (p_menu_item) activate callback user_data)

Pour permettre agrave lutilisateur dacceacuteder aux diffeacuterents eacuteleacutements du menu agrave laide de la touche ltAltgt nous utilisonsdes mneacutemoniques par exemple pour quitter leacutediteur il suffit de faite Alt+F puis Q Et voici le code pour creacuteer nossix eacuteleacutements du menu

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau G_CALLBACK (cb_new) user_data) menu_item_new (GTK_MENU (p_menu) _Ouvrir G_CALLBACK (cb_open) user_data) menu_item_new (GTK_MENU (p_menu) _Enregistrer G_CALLBACK (cb_save) user_data) menu_item_new (GTK_MENU (p_menu) Enregistrer _sous G_CALLBACK (cb_saveas) user_data) menu_item_new (GTK_MENU (p_menu) _Fermer G_CALLBACK (cb_close) user_data) menu_item_new (GTK_MENU (p_menu) _Quitter G_CALLBACK (cb_quit) user_data)

Voilagrave notre menu est creacuteeacute il nous reste plus quagrave linteacutegrer agrave notre fenecirctre

mainc gtk_box_pack_start (GTK_BOX (p_main_box) GTK_WIDGET (menu_new (p_text_view)) FALSE FALSE 0)

Le problegraveme cest que nous avons besoin de passer le GtkTextView lors de la creacuteation du menu (qui est utiliseacute par lesfonctions cb_new et cb_open) or celui-ci est creacuteeacute apregraves le menu (puisque nous creacuteons les widgets dans lordre ougrave ilfaut les inteacutegrer agrave linterface (8) ) nous devons creacuteer le GtkTextView (seul lappel agrave gtk_text_view_new est deacuteplaceacute)

XII-C - Code source

chapitre12zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 36 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIII - Les barres doutils

XIII-A - Aperccedilu

Cliquez pour agrandir

XIII-B - Creacuteation dune barre doutils

La creacuteation dune barre doutils ressemble fort agrave celle dun menu en plus simple puisquil ny a pas de sous menu on creacutee notre barre doutils (gtk_toolbar_new) puis les eacuteleacutements de la barre pour cela on utilise des boutons(gtk_tool_button_new_from_stock) que lon inseacutere dans la barre (gtk_toolbar_insert) Pas conseacutequent notre fichierbarreoutilsc ressemble agrave menuc

barreoutilscinclude ltgtkgtkhgtinclude callbackhinclude barreoutilsh

static void toolbar_item_new (GtkToolbar const gchar GCallback gpointer)

GtkToolbar toolbar_new (gpointer user_data) GtkWidget p_toolbar = NULL

p_toolbar = gtk_toolbar_new () toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_NEW G_CALLBACK (cb_new) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_OPEN G_CALLBACK (cb_open) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE G_CALLBACK (cb_save) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE_AS G_CALLBACK (cb_saveas) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_CLOSE G_CALLBACK (cb_close) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_QUIT G_CALLBACK (cb_quit) user_data) return GTK_TOOLBAR (p_toolbar)

static void toolbar_item_new (GtkToolbar p_toolbar const gchar stock_id GCallback callback gpointer user_data) GtkToolItem p_tool_item = NULL

p_tool_item = gtk_tool_button_new_from_stock (stock_id) g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data) gtk_toolbar_insert (p_toolbar p_tool_item -1)

Le code nest pas complet car lorsque jexeacutecute le programme GTK+ affiche en plus des icocircnes le texte sous lesboutons Pour modifier cela il suffit dajouter une ligne de code

barreoutilsc gtk_toolbar_set_style (GTK_TOOLBAR (p_toolbar) GTK_TOOLBAR_ICONS)

Pourquoi gtk_tool_button_new_from_stock retourne un GtkToolItem et non un GtkWidgetcomme nous avons eacuteteacute habitueacute jusquagrave preacutesent Il sagit dune bizarrerie de GTK+ dontje ne connais pas la raison

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 37 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour anticiper un changement dinterface (dans GTK+ 30 peut ecirctre ) nous aurions pueacutecrire

Gtkwidget p_tool_item = NULL

p_tool_item = GTK_WIDGET (gtk_tool_button_new_from_stock (stock_id))g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data)gtk_toolbar_insert (p_toolbar GTK_TOOL_ITEM (p_tool_item) -1)

XIII-C - Code source

chapitre13zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 38 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIV - Les racourcis clavier

XIV-A - Aperccedilu

Cliquez pour agrandir

XIV-B - Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mneacutemoniques ces derniers permettent dacceacuteder agrave un eacuteleacutementseacutequentiellement alors que les raccourcis appellent une fonction si lutilisateur appuie simultaneacutement sur une ouplusieurs touches (geacuteneacuteralement de la forme ltModificateurgtTouche ougrave Modificateur repreacutesente les touches ShiftAlt et Control) Ce raccourci peut ecirctre attacheacute agrave un eacuteleacutement du menu mais ceci nest pas obligatoire

Les raccourcis sont regroupeacutes en groupe dans un GtkAccelGroup quil faut commencer par creacuteer

raccourciscinclude ltgtkgtkhgtinclude callbackhinclude raccourcish

GtkAccelGroup accel_group_new (gpointer user_data) GtkAccelGroup p_accel_group = NULL

p_accel_group = gtk_accel_group_new () return p_accel_group

Vous commencez agrave avoir lhabitude de cette organisation nous allons donc creacuteer une fonction qui va se chargerdajouter un raccourci au groupe

raccourciscstatic void accelerator_new (GtkAccelGroup p_accel_group const gchar accelerator const gchar accel_path GCallback callback gpointer user_data) guint key GdkModifierType mods GClosure closure = NULL

gtk_accelerator_parse (accelerator ampkey ampmods) closure = g_cclosure_new (callback user_data NULL) gtk_accel_group_connect (p_accel_group key mods GTK_ACCEL_VISIBLE closure) gtk_accel_map_add_entry (accel_path key mods)

La fonction gtk_accelerator_parse permet de deacutecomposer une chaicircne de caractegraveres de la forme ltControlgtF1 ouencore ltAltgtA en numeacutero de touche et modificateur

En plus des touches pour creacuteer un raccourci clavier nous avons besoin dune fonction agrave appeler lorsque lutilisateurappuie sur les touches speacutecifieacutees gtk_accel_group_connect attend une fonction du type GClosure regardons ladocumentation de gobject pour savoir agrave quoi cela correspond

typedef struct

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 7 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

maincinclude ltstdlibhgt

int main (int argc char argv) return EXIT_SUCCESS

Pour pouvoir utiliser les fonctions de GTK+ il faut bien sucircr inclure le fichier den-tecircte correspondant

include ltgtkgtkhgt

La premiegravere chose agrave faire est dinitialiser la machinerie GTK+ gracircce agrave la fonction gtk_init

void gtk_init (int argc char argv)

Cette fonction reccediloit les arguments passeacutes en ligne de commande ceux qui sont speacutecifiques agrave GTK+ sont ensuiteretireacutes de la liste dougrave lutilisation des pointeurs

Ensuite il nous faut creacuteer tous les widgets dont nous avons besoin si neacutecessaire modifier leurs paramegravetres pardeacutefaut les connecter agrave des fonctions callback et ensuite demander leur affichage (tout ceci sera expliciteacute dans lasuite du tutoriel) Une fois la fenecirctre principale creacuteeacutee il suffit de lancer la boucle principale de GTK+

void gtk_main (void)

Cette fonction est une boucle sans fin (seule la fonction gtk_main_quit permet den sortir) qui se charge de geacuterer ledeacuteroulement de notre programme (affichage des widgets envoi de signaux)

Voici donc notre premier programme en CGTK+ qui ne fait rien

maincinclude ltstdlibhgtinclude ltgtkgtkhgt

int main (int argc char argv) Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application

Lancement de la boucle principale gtk_main() return EXIT_SUCCESS

En plus de ne rien faire notre programme ne peut ecirctre termineacute que de faccedilon brutale (Ctrl+C) puisque nous nappelonspas la fonction gtk_main_quit

I-H - Code source

chapitre1zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 8 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

II - Notre premiegravere fenecirctre

II-A - Aperccedilu

II-B - Creacuteation

La fenecirctre principale est repreacutesenteacutee par la classe GtkWindow

La creacuteation dune fenecirctre se fait simplement en appelant le constructeur de cette classe la fonction gtk_window_new

GtkWidget gtk_window_new (GtkWindowType type)

Le seul paramegravetre de cette fonction est le type de fenecirctre souhaiteacute Il ny a que deux possibiliteacutes

bull GTK_WINDOW_TOPLEVEL une fenecirctre classique (cest la base de notre application)

bull GTK_WINDOW_POPUP il sagit dune fenecirctre avec seulement lespace de travail (pas de bordure ni demenu systegraveme)

Cette fonction renvoie un pointeur sur une structure de type GtkWindow (transformer en GtkWidget gracircce aupolymorphisme) qui est lentiteacute qui va nous servir agrave manipuler notre fenecirctre

II-C - Affichage

Si vous essayez deacutecrire un code maintenant vous ne verrez rien pourquoi Tout simplement parce quil faut preacuteciseragrave GTK+ quil faut rendre notre fenecirctre visible gracircce agrave la fonction gtk_widget_show

void gtk_widget_show (GtkWidget widget)

Voici le code qui permet dafficher notre premiegravere fenecirctre

maincinclude ltstdlibhgtinclude ltgtkgtkhgt

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL)

Affichage de la fenetre principale gtk_widget_show (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 9 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Ceux qui se sont essayeacutes agrave la creacuteation dapplications graphiques avec lAPI Windows comprendront la simpliciteacutede ce code

II-D - Destruction

Dans lexemple preacuteceacutedent si vous avez essayeacute de terminer lapplication en fermant la fenecirctre (Alt+F4 ou en cliquantsur la petite croix) vous vous ecirctes peut-ecirctre aperccedilu que lapplication tournait encore en fond cest le mecircme problegravemeque pour le chapitre preacuteceacutedent on ne fait pas appel agrave gtk_main_quit Mais comment appeler cette fonction puisquequune fois gtk_main appeleacutee nous ne pouvons rien faire Cest lagrave quintervient le meacutecanisme des callback A chaqueeacuteveacutenement qui se produit la bibliothegraveque GObject produit un signal si nous souhaitons modifier le comportementpar deacutefaut du signal il suffit de connecter notre fonction callback agrave leacuteveacutenement souhaiteacute

define g_signal_connect(instance detailed_signal c_handler data)

Cette macro permet dintercepter leacuteveacutenement detailed_signal de lobjet instance gracircce agrave la fonction c_handler quidoit ecirctre du type GCallback

void (GCallback) (void)

Les fonctions callback peuvent bien sucircr recevoir des paramegravetres mais leur nature et leur nombre deacutependent ducontexte tout est geacutereacute par la bibliothegraveque GObject Le prototype le plus courant pour une fonction de rappel estle suivant

void callback (GtkWidget p_widget gpointer user_data)

Dont le premier paramegravetre est le widget qui a reccedilu le signal et le second correspond au paramegravetre data de la fonctiong_signal_connect qui nous permet de passer des informations aux fonctions callback Pour finir proprement notreapplication il suffit dintercepter le signal destroy de notre fenecirctre et dy assigner la fonction gtk_main_quit qui neprend pas dargument Voici donc notre premiegravere application fonctionnelle

maincinclude ltstdlibhgtinclude ltgtkgtkhgt

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (gtk_main_quit) NULL)

Affichage de la fenetre principale gtk_widget_show (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

Il est plus courant de creacuteer notre propre fonction de rappel pour quitter le programme ceci permet de libeacuterer lameacutemoire alloueacutee fermer les fichiers ouverts

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 10 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

maincinclude ltstdlibhgtinclude ltgtkgtkhgt

void cb_quit (GtkWidget gpointer)

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (cb_quit) NULL)

Affichage de la fenetre principale gtk_widget_show (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

void cb_quit (GtkWidget p_widget gpointer user_data) gtk_main_quit()

Parametres inutilises (void)p_widget (void)user_data

Le preacutefixe cb_ permet de diffeacuterencier les fonctions callback quil est preacutefeacuterable de regrouper dans un ou plusieursfichiers seacutepareacutes

A la fin de la fonction je transtype les paramegravetres inutiliseacutes pour eacuteviter que moncompilateur mindique des variables non utiliseacutees cest le problegraveme avec les fonctionscallback lAPI nous impose un prototype

II-E - Code source

chapitre2zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 11 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

III - Fermer notre fenecirctre gracircce aux boutons

III-A - Aperccedilu

III-B - Les boutons poussoir

Maintenant que notre programme se termine proprement il est plus convivial de proposer agrave lutilisateur un boutonpour quitter Pour creacuteer un bouton poussoir il existe plusieurs possibiliteacutes

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 premiegravere fonction creacutee un bouton qui peut servir pour contenir nimporte quel autre widget (label image) Si voussouhaitez creacuteer un bouton avec du texte dessus utilisez directement la seconde fonction qui prend en argument letexte agrave afficher Si vous souhaitez ajouter un raccourci clavier (accessible avec la touche Alt) la troisiegraveme fonctionpermet den speacutecifier un en faisant preacuteceacuteder une lettre (geacuteneacuteralement la premiegravere) dun underscore _ (si voussouhaitez afficher le caractegravere _ il faut en mettre deux) Enfin la derniegravere fonction permet dutiliser les Stock Itemsqui sont un ensemble deacuteleacutements preacutedeacutefinis par GTK+ pour les menus et barres doutils Le seul paramegravetre de cettefonction est le nom de leacuteleacutement et GTK+ se charge dafficher licocircne approprieacutee ainsi que le texte suivant la languechoisie et un raccourci

Cest bien sucircr cette derniegravere fonction que nous allons utiliser et ce le plus souvent possible Voici le code pour creacuteerun tel bouton

maincGtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_QUIT)

Pour obtenir tous les types de stocks items disponibles GtkStockItem

Bien sucircr comme pour la fenecirctre si lon veut voir quelque chose il faut demander agrave GTK+ dafficher notre widget

maincgtk_widget_show (p_button)

Mais pas seulement En effet il faut preacuteciser agrave GTK+ ougrave doit ecirctre afficheacute notre bouton Pour cela la classe GtkWindowest deacuteriveacutee de la classe GtkContainer qui est comme son nom le laisse penser un conteneur pour widget Pourajouter un widget il suffit de faire appel agrave la fonction gtk_container_add

void gtk_container_add (GtkContainer container GtkWidget widget)

Le premier paramegravetre de cette fonction est un GtkContainer or nous souhaitons passer notre fenecirctre qui est unGtkWidget pour ne pas avoir de problegravemes il faut utiliser le systegraveme de macro offert par GTK+ pour transtyper notreGtkWidget en GtkContainer (eh oui en C le polymorphisme a ses limites)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 12 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

maincgtk_container_add (GTK_CONTAINER (p_window) p_button)

Ce meacutecanisme de transtypage permet agrave GTK+ de veacuterifier que notre GtkWidget est bien compatible avec lutilisationque lon souhaite en faire En cas deacutechec GTK+ nous preacutevient en affichant un message dans la console

(gtk_boutonexe1044) Gtk-CRITICAL gtk_container_add assertion `GTK_IS_CONTAINER (container) failed

Pour finir il faut connecter notre bouton pour appeler notre fonction cb_quit lorsque lutilisateur clic dessus (ce quicorrespond agrave leacuteveacutenement clicked)

g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_quit) NULL)

Pour eacuteviter dappeler la fonction gtk_widget_show pour tous les widgets de notreapplication on peut se contenter dun seul appel agrave la fonction gtk_widget_show_all quipermet dafficher tous les widgets contenus dans celui passeacute agrave la fonction

maincinclude ltstdlibhgtinclude ltgtkgtkhgtinclude callbackh

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (cb_quit) NULL)

GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_QUIT) gtk_container_add (GTK_CONTAINER (p_window) p_button) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_quit) NULL)

Affichage de la fenetre principale gtk_widget_show_all (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

III-C - Code source

chapitre3zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 13 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IV - Comment afficher plusieurs widgets

IV-A - Aperccedilu

IV-B - Le problegraveme

Dans la partie preacuteceacutedente nous avons reacuteussi agrave afficher un bouton dans la fenecirctre de notre application Si vous avezessayeacute dajouter un second widget GTK+ agrave ducirc vous reacutepondre poliment

(gtk_boxexe492) Gtk-WARNING Attempting to add a widget with typeGtkButton to a GtkWindow but as a GtkBin subclass a GtkWindow can only containone widget at a time it already contains a widget of type GtkButton

Les plus anglophiles dentre vous auront compris que GTK+ naccepte pas lajout un second widget dans notre fenecirctretout simplement parce quil y en a deacutejagrave un et que la sous classe GtkBin (classe megravere de notre GtkWindow) ne peutcontenir quun seul widget

IV-C - La solutions

Pour contourner ce problegraveme il faut commencer par creacuteer un widget qui accepte den contenir plusieurs autrespour ensuite y ajouter tout ce dont nous avons besoin Pour linstant nous utiliserons quun seul widget (il existetrois classes qui permettent ceci) il sagit des GtkBox Il sagit de la meacutethode que jutilise le plus souvent Ce nestpeut-ecirctre pas la plus simple agrave maicirctriser mais elle extrecircmement souple et puissante Elle consiste agrave creacuteer une boicirctepuis agrave y ajouter les widgets les uns apregraves les autres (soit au deacutebut soit agrave la fin) Il existe deux classes heacuteritant deGtkBox les GtkVBox qui empilent les widgets dans le sens vertical et les GtkHBox qui font de mecircme mais dansle sens horizontal Les fonctions pour manipuler ces deux classes sont les mecircmes seule la fonction pour les creacuteerportent un nom diffeacuterent

GtkWidget gtk_vbox_new (gboolean homogeneous gint spacing)GtkWidget gtk_hbox_new (gboolean homogeneous gint spacing)

Le paramegravetre homogeneous permet de reacuteserver pour chaque widget une zone de taille identique (zone que le widgetnest pas obligeacute de remplir) et spacing permet dajouter une bordure en pixels (espacement autour de la GtkBox)Ensuite il suffit dajouter les diffeacuterents widgets gracircce aux fonctions

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)

Qui ajoutent reacuteciproquement le widget child au deacutebut et agrave la fin de box Le paramegravetre expand permet au widget davoirle plus de place possible (si le paramegravetre homogeneous vaut TRUE cette option a aucun effet) Si plusieurs widgetont ce paramegravetre agrave TRUE ils se partagent de faccedilon eacutegale lespace Loption fill permet au widget de remplir toutlespace qui lui ait reacuteserveacute

Pour reacuteellement comprendre linfluence de ces paramegravetres il faut faire des tests en modifiant un agrave un chaqueparamegravetre et observer les effets dun redimentionnement de la fenecirctre principale

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 14 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Le plus gecircnant avec cette meacutethode cest quil faut jongler entre les GtkHBox et les GtkVBox en les imbriquant pourobtenir le reacutesultat souhaiter nheacutesitez pas agrave utiliser une feuille et un crayon )

Pour en revenir agrave notre eacutediteur de texte nous allons preacuteparer notre application agrave contenir les futurs widgetsNous utilisons un GtkVBox pour lensemble des widgets (il sagit de la boicircte principale qui pourra contenir dautresGtkContainer selon nos besoins)

maincinclude ltstdlibhgtinclude ltgtkgtkhgtinclude callbackh

int main (int argc char argv) GtkWidget p_window = NULL GtkWidget p_main_box = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (cb_quit) NULL)

Creation du conteneur principal p_main_box = gtk_vbox_new (FALSE 0) gtk_container_add (GTK_CONTAINER (p_window) p_main_box)

Creation du bouton Quitter GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_QUIT) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_quit) NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_button FALSE FALSE 0)

Affichage de la fenetre principale gtk_widget_show_all (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

IV-D - Code source

chapitre4zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 15 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

V - Afficher le contenue dun fichier

V-A - Aperccedilu

Cliquez pour agrandir

V-B - Saisir du texte

Les choses seacuterieuses vont commencer il sagit de mettre en place le widget qui va nous permettre dafficher etdeacutediter du texte Il sagit de la classe GtkTextView Gracircce agrave GTK+ la mise en place est toujours aussi simple

mainc GtkWidget p_text_view = NULL Creation de la zone de texte p_text_view = gtk_text_view_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_text_view TRUE TRUE 0)

Comme il sagit de la partie centrale de notre application nous demandons agrave ce quelle prenne le plus de placepossible (gracircce agrave la fonction gtk_box_pack_start)

Puisque nous voulons afficher les boutons en dessous de la zone de texte il faut ajouter ce morceau de code avantcelui creacuteant le bouton

V-C - Ouvrir un fichier

Maintenant nous avons une belle zone de texte il faut la remplir avec le contenu dun fichier Pour ce faire nousallons commencer par ajouter un bouton ouvrir

mainc Creation du bouton Ouvrir GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_OPEN) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_open) p_text_view) gtk_box_pack_start (GTK_BOX (p_main_box) p_button FALSE FALSE 0)

Si vous exeacutecutez le programme maintenant (3) vous remarquerez que les boutons sont ajouteacutes les uns en dessousdes autres ce qui diminue la zone de saisie (avec deux boutons ce nest pas gecircnant mais au bout dune dizaineccedila risque decirctre probleacutematique) Pour pallier ce problegraveme nous allons utiliser un nouveau style de GtkBox lesGtkButtonBox qui sont preacutevus pour contenir des boutons (ccedila tombe plutocirct bien D) Donc pour eacuteviter de diminuerla zone de saisie et comme nous avons de la place en largueur nous allons utiliser un GtkHButtonBox qui va ecirctreinclus dans la p_main_box Voici les modifications agrave effectuer

mainc GtkWidget p_button_box = NULL Creation du conteneur pour les boutons p_button_box = gtk_hbutton_box_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_button_box FALSE FALSE 0)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 16 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc gtk_box_pack_start (GTK_BOX (p_button_box) p_button FALSE FALSE 0) gtk_box_pack_start (GTK_BOX (p_button_box) p_button FALSE FALSE 0)

Maintenant il nous reste plus quagrave creacuteer la fonction cb_open dans le fichier callbackc pour linstant nous nouscontenterons douvrir toujours le mecircme fichier nous verrons plus tard comment laisser le choix agrave lutilisateur

callbackcdefine DEFAULT_FILE mainc

void cb_open (GtkWidget p_widget gpointer user_data) open_file (DEFAULT_FILE GTK_TEXT_VIEW (user_data))

Parametre inutilise (void)p_widget

Vous aurez compris que lon va deacuteleacuteguer tout le travail agrave la fonction open_file qui devra ouvrir le fichier dont le nomest passeacute en premier paramegravetre pour lafficher dans le GktTextView

Jai fait ce choix pour deux raisons le code dune fonction callback peut ecirctre tregraves conseacutequent (surtout si lon souhaitequelle affiche une boicircte de dialogue) et aussi parce que cb_open nest peut ecirctre pas la seule fonction agrave copierun fichier dans un GtkTextView (par exemple lors de la creacuteation dun nouveau fichier lon peut vouloir copier unsquelette de fichier)

Pour copier notre fichier plutocirct que dutiliser la fonction fgets nous allons nous servir de la glib (4) qui proposela fonction

gboolean g_file_get_contents (const gchar filename gchar contents gsize length GError error)

Qui nous renvoit le contenu du fichier nommeacute filename dans le tampon contents Il est possible de reacutecupeacuterer lenombre de caractegraveres copieacutes et retourne TRUE en cas de succegraves sinon FALSE et dans ce cas une structure de typeGError est creacutee pour en savoir plus sur le type derreur rencontreacute

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView else print_warning (Impossible douvrir le fichier sn file_name)

Je pense quun certain nombre dexplications simpose (surtout si je vais trop vite nheacutesitez pas agrave marrecircter )

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 17 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

bull g_return_if_fail est une macro qui peut ecirctre compareacutee agrave assert sauf quelle se contente de sortir de la fonctionsi lexpression passeacutee en paramegravetre est fausse Cest une meacutethode pratique pour veacuterifier la validiteacute desparamegravetres (si la fonction doit retourne une valeur utiliseacute plutocirct g_return_val_if_fail qui prend un secondparamegravetre la valeur agrave retourner)

bull Ensuite on essaie de reacutecupeacuterer le contenu de notre fichier

bull Si cela eacutechoue nous le signalons agrave lutilisateur agrave laide de la fonction print_warning

bull Le type gchar est une redeacutefinition du type char par la glib (il en va de mecircme pour tous les autres types du C)privileacutegiez ces types lorsque vous utilisez des fonctions de cette bibliothegraveques

Mais quest-ce donc cette fonction print_warning Cest une fonction que nous allons creacuteer semblable agrave printf quisignalera agrave lutilisateur quune erreur non critique est survenue Comme nous navons pas encore abordeacute les boicirctesde dialogue pour afficher un message il sagira pour linstant dune simple redeacutefinition de printf Pendant que noussommes dans laffichage des messages nous allons aussi creacuteer deux fonctions print_info et print_error qui vontrespectivement afficher un message dinformation et un message derreur critique (ce qui entraicircne la terminaison duprogramme) tout ceci dans un nouveau fichier errorc

errorhifndef H_ERRORdefine H_ERROR

void print_info (char )void print_warning (char )void print_error (char )

endif not H_ERROR

errorcinclude ltstdarghgtinclude ltstdiohgtinclude ltstdlibhgtinclude errorh

void print_info (char format ) va_list va

va_start (va format) printf (Information ) vprintf (format va) printf (n)

void print_warning (char format ) va_list va

va_start (va format) fprintf (stderr Erreur ) vfprintf (stderr format va) fprintf (stderr n)

void print_error (char format ) va_list va

va_start (va format) fprintf (stderr Erreur fatale ) vfprintf (stderr format va) fprintf (stderr n) exit (EXIT_FAILURE)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 18 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

Pour en finir avec louverture dun fichier il nous reste agrave copier contents dans le GtkTextView En fait le GtkTextViewne gegravere que la forme pour modifier le contenu il faut passer par les GtkTextBuffer Commenccedilons donc par reacutecupeacutererce fameux GtkTextBuffer

callbackc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (p_text_view)

Et pour finir on utilise la fonction

void gtk_text_buffer_insert (GtkTextBuffer buffer GtkTextIter iter const gchar text gint len)

Reacutecapitulons buffer est le GtkTextBuffer que lon vient de reacutecupeacuterer text cest le texte agrave afficher et len la taille dece dernier (ou -1 sil sagit dune chaicircne de caractegraveres au sens du langage C)

Mais quest-ce donc ce GtkTextIter On peut voir cela comme un curseur virtuel qui indique la position agrave laquelleeffectuer linsertion de texte dans le GtkTextBuffer (5) Allons voir ce que la documentation peut nous apprendreagrave leur sujet (6)

typedef struct GtkTextIter is an opaque datatype ignore all these fields Initialize the iter with gtk_text_buffer_get_iter_ functions GtkTextIter

Voilagrave on a notre solution suffit de rechercher les fonctions commenccedilant par gtk_text_buffer_get_iter_ voici la liste

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)

La fonction gtk_text_buffer_get_iter_at_line fait parfaitement laffaire

callbackc GtkTextIter iter

gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1)

Cependant si vous ne voulez pas avoir de problegravemes avec le codage des caractegraveres il vaut mieux convertir le codagelocal vers utf8 Voici le reacutesultat final

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 19 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gchar utf8 = NULL GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_text_buffer_insert (p_text_buffer ampiter utf8 -1) g_free (utf8) utf8 = NULL

V-D - La petite touche finale

Pour finir cette laborieuse partie sur une petite touche estheacutetique nous allons demander agrave GTK+ de nous lancerlapplication en plein eacutecran Pour se faire il suffit dajouter lors de la creacuteation de la fenecirctre principale

maincgtk_window_maximize (GTK_WINDOW (p_window))

On peut mecircme se permettre une pointe dexcentriciteacute en modifiant le titre de notre fenecirctre

maincgtk_window_set_title (GTK_WINDOW (p_window) Editeur de texte en GTK+)

V-E - Code source

chapitre5zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 20 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VI - Choisir un fichier

VI-A - Aperccedilu

Cliquez pour agrandir

VI-B - Utilisation dun GtkFileChooserFile

Jusquagrave preacutesent lutilisateur navait pas le choix quant au fichier agrave ouvrir heureusement GTK+ vient agrave notre aide gracircceau widget GtkFileChooserFile qui est tout simplement une boicircte de dialogue qui propose agrave lutilisateur de seacutelectionnerun fichier dans son arborescence disque

Commenccedilons par creacuteer notre boicircte de dialogue dans la fonction cb_open

callbackcvoid cb_open (GtkWidget p_widget gpointer user_data) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Ouvrir un fichier NULL GTK_FILE_CHOOSER_ACTION_OPEN GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_OPEN GTK_RESPONSE_ACCEPT NULL)

Cette fonction neacutecessite le titre de la boicircte de dialogue une fenecirctre parente le type daction (ici on souhaite ouvrir unfichier GTK+ autorisera lutilisateur agrave seacutelectionner uniquement les fichiers existants) Pour finir il sagit dun couple devaleurs GTK_STOCK_ITEMGTK_STOCK_RESPONSE qui permet de creacuteer un bouton utilisant le stock ID speacutecifieacuteet lorsque celui-ci est cliqueacute la fonction servant agrave lancer la boicircte de dialogue retournera le reacuteponse ID correspondantIl existe une seacuterie de valeurs deacutefinies par GTK+ quil est conseilleacute dutiliser

typedef enum GTK returns this if a response widget has no response_id or if the dialog gets programmatically hidden or destroyed GTK_RESPONSE_NONE = -1

GTK wont return these unless you pass them in as the response for an action widget They are for your convenience GTK_RESPONSE_REJECT = -2 GTK_RESPONSE_ACCEPT = -3

If the dialog is deleted GTK_RESPONSE_DELETE_EVENT = -4

These are returned from GTK dialogs and you can also use them yourself if you like GTK_RESPONSE_OK = -5 GTK_RESPONSE_CANCEL = -6 GTK_RESPONSE_CLOSE = -7 GTK_RESPONSE_YES = -8

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 21 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GTK_RESPONSE_NO = -9 GTK_RESPONSE_APPLY = -10 GTK_RESPONSE_HELP = -11 GtkResponseType

Nous indiquons la fin des couples stock idreacuteponse id avec la valeur NULL

Une fois la boicircte de dialogue creacuteee on demande agrave GTK+ de lafficher gracircce agrave la fonction gtk_dialog_run puis onreacutecupegravere sa valeur de retour qui correspond au bouton cliqueacute par lutilisateur

callbackc if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

Ici ce qui nous inteacuteresse cest lorsque que lutilisateur clique sur le bouton ouvrir (donc gtk_dialog_run renvoieGTK_RESPONSE_ACCEPT) dans ce cas il nous suffit de reacutecupeacuterer le nom du fichier seacutelectionneacute puis de louvrir

callbackc gchar file_name = NULL

file_name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) open_file (file_name GTK_TEXT_VIEW (user_data)) g_free (file_name) file_name = NULL

Pour finir dans tous les cas on noublie pas de deacutetruire la boicircte de dialogue

callbackc gtk_widget_destroy (p_dialog)

Et voilagrave le travail lutilisateur peut ouvrir le fichier quil souhaite

VI-C - Code source

chapitre6zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 22 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VII - Interlude

Avant daller plus loin dans lameacutelioration de linterface de notre eacutediteur il est neacutecessaire de modifier sonfonctionnement interne (ne vous inquieacutetez je nai pas dit chambouler) en effet souvenez-vous dans lintroduction jaieacutevoqueacute la possibiliteacutes douvrir plusieurs documents gracircce agrave un systegraveme donglets Pour cela il faut sauvegarder lesproprieacuteteacutes de chaque document ouvert Pris agrave temps ce genre de modification nest pas trop lourde mais si nousattendons cela risque de devenir un vrai casse tecircte

Pour cela nous allons utiliser une structure de donneacutee pour chaque document ouvert qui devra garder en meacutemoirele chemin complet du fichier (ou NULL si le document nest pas encore sauvegarder) sil agrave eacutetait modifier depuis laderniegravere sauvegarde et le GtkTextView qui sert agrave son affichage Voici donc la structure qui va nous servir

documenthtypedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

Sachant que nous serons ameneacute agrave stocker plusieurs occurrences de cette structure il serait bon de reacutefleacutechir degravesmaintenant agrave la structure de donneacutee agrave utiliser pour les stocker La premiegravere ideacutee qui vient agrave lesprit est un tableaualloueacute dynamiquement cependant lutilisateur peut souhaiter fermer un document qui se trouve au milieu on estalors obligeacute de deacutecaler toutes les cellules en amont Dans ce cas il parait naturel dutiliser une liste chaicircneacutee Parchance la glib propose une bibliothegraveque de gestion des listes chaicircneacutees cela nous fera gagner du temps le momentvenu Pour linstant on se contente de creacuteer une structure de donneacutees qui contiendra tous les documents ouverts(stockeacutee dans une GList) et un pointeur sur le document actif (actuellement comme nous navons quun documentouvert en mecircme temps on manipulera uniquement ce pointeur)

documenthtypedef struct GList tous document_t actif docs_t

Maintenant se pose le problegraveme de savoir comment transmettre cette structure On pourrait se servir du paramegravetreuser_data preacutesent dans toutes les fonctions callback mais certaines fonctions utilise deacutejagrave ce paramegravetre (la fonctioncb_open par exemple) il faudrait creacuteer un champs suppleacutementaire dans notre structure documents_s Une solutionplus simple est de creacuteer une variable globale agrave lensemble du programme Ceux qui passe reacuteguliegraverement sur le forumC savent que cest fortement deacuteconseilleacute mais ici nous nous trouvons dans lune des rares exceptions agrave la regravegle Detoute faccedilon cela revient au mecircme que de passer ladresse de notre structure agrave toutes les fonctions callback Nousdeacutefinissons donc un nouveau fichier den-tecircte

documenthifndef H_DOCUMENTdefine H_DOCUMENT

include ltgtkgtkhgt

typedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 23 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

documenthtypedef struct GList tous document_t actif docs_t

extern docs_t docs

endif not H_DOCUMENT

Et dans le fichier mainc

maincinclude documenth

docs_t docs = NULL NULL

Pour linstant la seule fonction qui modifie leacutetat dun document est la fonction open_file il faut donc inclure documenthdans callbackc et modifier leacutegegraverement la fonction pour enregistrer le document ouvert

callbackc if (g_file_get_contents (file_name ampcontents NULL NULL)) Pour linstant il faut allouer la memoire par la suite on modifira simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = g_strdup (file_name) Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = p_text_view Le document vient detre ouvert il nest donc pas modifie docsactif-gtsauve = TRUE

Ne soyez pas choqueacute si je ne teste pas le retour de la fonction g_malloc pour veacuterifier quilnest pas NULL En effet cette derniegravere met fin agrave lapplication si lallocation eacutechoue

VII-A - Code source

chapitre7zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 24 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VIII - Sauvegarder les modification

VIII-A - Aperccedilu

Cliquez pour agrandir

VIII-B - Enregistrer

Avant de pouvoir sauvegarder un document il faut quil soit modifieacute Comment savoir que le contenu du fichier a eacuteteacutemodifier Gracircce au signal changed du GtkTextBuffer que nous interceptons gracircce agrave la fonction cb_modifie

mainc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (p_text_view)) g_signal_connect (G_OBJECT (p_text_buffer) changed G_CALLBACK (cb_modifie) NULL)

Cette derniegravere modifie simplement le champ sauve du document

callbackcvoid cb_modifie (GtkWidget p_widget gpointer user_data) if (docsactif) docsactif-gtsauve = FALSE

Pour la sauvegarde il faut distinguer deux cas soit il sagit de la premiegravere sauvegarde du fichier il faut alors demanderle nom du fichier agrave lutilisateur (cela ressemble fortement agrave louverture dun fichier) soit le fichier est deacutejagrave preacutesent surle disque il suffit de remplacer son contenu par celui du GtkTextViewer Nous avons convenu quun fichier qui neacutetaitpas encore enregistreacute avait sa proprieacuteteacute chemin agrave NULL

Bien sucircr cela na lieu que si un fichier est ouvert et quil a eacuteteacute modifieacute depuis sa derniegravere sauvegarde

callbackcvoid cb_save (GtkWidget p_widget gpointer user_data) if (docsactif) if (docsactif-gtsauve) Le fichier na pas encore ete enregistre if (docsactif-gtchemin) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Sauvegarder le fichier NULL GTK_FILE_CHOOSER_ACTION_SAVE GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_SAVE GTK_RESPONSE_ACCEPT NULL) if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 25 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc docsactif-gtchemin = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) gtk_widget_destroy (p_dialog) Soit le fichier a deja ete enregistre soit lutilisateur vient de nous fournir son nouvel enplacement on peut donc lenregistrer if (docsactif-gtchemin) else print_warning (Aucun document ouvert)

Il nous reste plus quagrave reacutecupeacuterer le contenu du GtkTextViewer et le copier dans le fichier chemin sans oublier dereconvertir le texte dans le codage local

callbackc FILE fichier = NULL

fichier = fopen (docsactif-gtchemin w) if (fichier) gchar contents = NULL gchar locale = NULL GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) contents = gtk_text_buffer_get_text (p_text_buffer ampstart ampend FALSE) locale = g_locale_from_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL fprintf (fichier s locale) g_free (locale) locale = NULL fclose (fichier) fichier = NULL docsactif-gtsauve = TRUE else print_warning (Impossible de sauvegarder le fichier s docsactif-gtchemin)

Le dernier paramegravetre de la fonction gtk_text_buffer_get_text est mis agrave FALSE car nous ne voulons pas enregistrerles caractegraveres invisibles preacutesent dans le GtkTextBuffer Ces caractegraveres servent agrave mettre en forme le texte (taillecouleur) nous pourrions creacuteer un nouveau format de fichier pour enregistrer la mise en forme

VIII-C - Enregistrer sous

Pour enregistrer notre document sous un autre nom il suffit de faire croire agrave cb_save que le document na pas encoreeacutetait enregistreacute tout simplement en changeant chemin agrave NULL et sauve agrave FALSE

callbackcvoid cb_saveas (GtkWidget p_widget gpointer user_data)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 26 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (docsactif) document_t tmp = docsactif

docsactif-gtchemin = NULL docsactif-gtsauve = FALSE cb_save (p_widget user_data) if (docsactif-gtsauve) (docsactif) = tmp else print_warning (Aucun document ouvert)

Il ne faut pas oublier que lutilisateur peut annuler lenregistrement de ce fait nous sauvegardons leacutetat du documentet si la sauvegarde na pas eu lieu on le restaure

VIII-D - Code source

chapitre8zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 27 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IX - Creacuteer un nouveau document

IX-A - Aperccedilu

Cliquez pour agrandir

IX-B - Nouveau fichier

Maintenant que lutilisateur peut ouvrir et fermer un fichier il est inteacuteressant de lui donner la possibiliteacute den creacuteerun nouveau Je ne reviens pas sur la creacuteation du bouton (ccedila devrait deacutejagrave ecirctre fait D) passons directement agrave lafonction cb_new

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) Pour linstant il faut allouer la memoire par la suite on modifiera simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = NULL Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = GTK_TEXT_VIEW (user_data) Le document vient detre creer il nest donc pas modifie docsactif-gtsauve = TRUE gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Je ne sais pas vous mais pour ma part jai fait un copiercoller de la fonction open_file Et oui ouvrir un document peutse reacutesumer agrave creacuteer un document vide puis remplir le GtkTextView avec le fichier souhaiteacute On peut donc simplifiernotre fonction open_file ainsi

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

cb_new (NULL p_text_view) gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE) p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1) Nous sommes obliges de remetre sauve a TRUE car linsertion du contenu du fichier dans le GtkTextView a appele cb_modfie docsactif-gtsauve = TRUE else print_warning (Impossible douvrir le fichier sn file_name)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 28 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc

Cest beau la factorisation du code Par contre nous sommes obligeacutes de remettre sauve agrave TRUE car nous avonsmodifieacute le GtkTextBuffer

IX-C - Code source

chapitre9zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 29 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

X - Fermer

X-A - Aperccedilu

Cliquez pour agrandir

X-B - Fermer un fichier

Maintenant que nous allouons de la meacutemoire il faut la libeacuterer agrave un endroit Logiquement cela va ecirctre fait agrave la fermeturedu document en guise dexercice je vous laisse creacuteer le bouton dans notre boicircte agrave bouton

Allez je vous aide le stock id correspondant est GTK_STOCK_CLOSE

Voilagrave maintenant si tout cest bien passeacute vous devriez ecirctre arriveacute dans le fichier callbackc avec quelque choseressemblant agrave

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data)

Lorsque lon ferme un document il faut vider le GtkTextView (avec les onglets on se contentera de le supprimer)pour cela il faut reacutecupeacuterer le deacutebut et la fin du GtkTextBuffer et demander agrave GTK+ de supprimer tout ce qui ce trouveentre les deux iteacuterateurs

callbackc Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) gtk_text_buffer_delete (p_text_buffer ampstart ampend) else print_warning (Aucun document ouvert)

Bien sucircr il ne faut pas oublier de libeacuterer la meacutemoire

callbackc g_free (docsactif-gtchemin) docsactif-gtchemin = NULL docsactif-gtp_text_view = NULL g_free (docsactif) docsactif = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 30 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour symboliser la fermeture dun document nous deacutesactivons le GtkTextView lors de la fermeture (ne pas oublierde le faire aussi dans mainc)

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) FALSE)

Et nous le reacuteactivons lors de louverture si celle si reacuteussie

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Lorsque lutilisateur quitte lapplication il faut bien sucircr fermer le document sil y en a un ouvert

void cb_quit (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data) gtk_main_quit()

Et aussi lorsquil creacuteeacute un nouveau document (et par conseacutequent lorsquil ouvre un fichier puisque lon fait appel agravecb_new)

void cb_new (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data)

X-C - Enregistrer avant de fermer

Si le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde geacuteneacuteralement le programme le signale agrave lutilisateur etlui propose de sauvegarder ou dannuler la fermeture Pour se faire nous devons modifier la fonction cb_close avantde fermer le document nous allons afficher une boicircte de dialogue

Pour creacuteer une boicircte de dialogue simplement il existe la classe GtkDialog et comme nous avons besoin de boutons(pour que lutilisateur fasse son choix) nous allons creacuteer notre boicircte avec la fonction

GtkWidget gtk_dialog_new_with_buttons (const gchar title GtkWindow parent GtkDialogFlags flags const gchar first_button_text )

Nous retrouvons les mecircmes options que pour le GtkFileChooserDialog mis agrave part option du type GtkDialogFlags

typedef enum GTK_DIALOG_MODAL = 1 ltlt 0 appel gtk_window_set_modal (win TRUE) GTK_DIALOG_DESTROY_WITH_PARENT = 1 ltlt 1 appel gtk_window_set_destroy_with_parent () GTK_DIALOG_NO_SEPARATOR = 1 ltlt 2 Pas de barre de separation au dessus des boutons GtkDialogFlags

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 31 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Nous nous contenterons de rendre notre fenecirctre modale (7)

Pour avoir accegraves agrave notre fenecirctre principale nous ajoutons un champs p_main_window agrave notre structure globaledocs_t que nous initialisons dans la fonction main

mainc docsp_main_window = GTK_WINDOW (p_window)

Il nous reste plus qua creacuteer notre boicircte de dialogue avec trois boutons Oui Non Annuler

callbackc if (docsactif-gtsauve) GtkWidget p_dialog = NULL

p_dialog = gtk_dialog_new_with_buttons (Sauvegarder docsp_main_window GTK_DIALOG_MODAL GTK_STOCK_YES GTK_RESPONSE_YES GTK_STOCK_NO GTK_RESPONSE_NO GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL NULL)

Nous obtenons donc une structure de type GtkDialog

typedef struct GtkWidget vbox GtkWidget action_area GtkDialog

Nous remarquons que cette structure contient deux membres qui permettent dacceacuteder agrave une GtkBox ougrave nous allonsajouter le contenu de la fenecirctre et agrave la partie contenant les boutons

Ensuite la construction de la fenecirctre est identique agrave celle de la fenecirctre principale ici nous nous contenterons dajouterun GtkLabel

callbackc GtkWidget p_label = NULL p_label = gtk_label_new (Voulez-vous sauvegarder les modifications ) gtk_box_pack_start (GTK_BOX (GTK_DIALOG (p_dialog)-gtvbox) p_label TRUE TRUE 0)

Une fois notre fenecirctre precircte il suffit de faire appel agrave la fonction gtk_dialog_run qui va afficher notre GtkDialog et nousretourner le reacuteponse id correspondant au bouton cliqueacute par lutilisateur

callbackc switch (gtk_dialog_run (GTK_DIALOG (p_dialog))) case GTK_RESPONSE_YES cb_save (p_widget user_data) break case GTK_RESPONSE_NO break case GTK_RESPONSE_CANCEL gtk_widget_destroy (p_dialog) return break

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 32 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc gtk_widget_destroy (p_dialog)

Si lutilisateur clique sur non on ne fait rien (le document sera simplement fermeacute) sur oui on enregistre avant defermer et pour finir sil annule on quitte la fonction

X-D - Code source

chapitre10zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 33 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XI - Les barres de deacutefilement

XI-A - Aperccedilu

Cliquez pour agrandir

XI-B - Ajouter des barres de deacutefilement

Apregraves le dernier chapitre quelque peu laborieux voici une partie plus simple mais qui va rendre notre applicationplus pratique En effet si vous avez essayeacute douvrir un fichier de grande taille vous avez pu remarquer que pourpouvoir lire la fin du fichier il fallait utiliser les touches du clavier pas tregraves convivial

Pour rendre la navigation plus aiseacutee on utilise des barres de deacutefilement

mainc GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_scrolled_window TRUE TRUE 0)

Creation de la zone de texte gtk_container_add (GTK_CONTAINER (p_scrolled_window) p_text_view)

Le constructeur de notre GtkScrolledWindow prend en argument deux GtkAdjustment qui permettent de deacutefinirdiffeacuterentes proprieacuteteacutes de la barre de deacutefilement (taille dune page la position de deacutepart) nous laissons GTK+ faireen passant NULL

Cest un bon deacutebut mais estheacutetiquement on peut faire mieux mecircme sil nest pas utile davoir une barre de deacutefilementelle est quand mecircme afficheacutee On peut demander agrave GTK+ de les afficher que si cela est neacutecessaire

mainc gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC)

En fait nous avons de la chance car la classe GtkTextView fait partie des widget qui supporte de faccedilon native les barresde deacutefilement Comment le savoir Ce genre de widget possegravede une ou deux proprieacuteteacutes de type GtkAdjustment (unepour la barre verticale lautre pour la barre horizontale) Actuellement seulement trois classes en sont capables lesGtkTextView les GtkTreeView et les GtkLayout

Comment faire pour les autres widgets Il faut passer par une classe adaptateur GtkViewport afin de creacuteer lesGtkAdjustment

XI-C - Code source

chapitre11zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 34 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XII - Les menus

XII-A - Aperccedilu

Cliquez pour agrandir

XII-B - Creacuteation du menu

Pour simplifier nous avons utiliseacute des boutons pour permettre agrave lutilisateur de creacuteer un document ouvrir un fichierMais il est plus courant dutiliser un menu pour afficher ces options GTK+ propose trois maniegraveres de creacuteer un menu

bull GtkItemFactory cette meacutethode est obsolegravete depuis la version 24 de GTK+

bull GtkUIManager cest ce quon appel une usine agrave gaz pour en savoir plus vous pouvez vous reporter aututoriel Utilisation de GtkUIManager

bull GtkMenu cest ce widget que nous allons eacutetudier il permet de creacuteer un menu manuellement (agrave lopposeacute deGtkUIManager)

Un menu selon GTK+ est composeacute de plusieurs eacuteleacutements

bull GtkMenuBar la barre de menu elle-mecircme

bull GtkMenu la partie deacuteroulante qui contient les diffeacuterents eacuteleacutements

bull GtkMenuItem cest sur ce widget que lutilisateur clique pour lancer une action

Pour commencer faisons linventaire de ce que nous avons besoin

bull Un GtkMenuBar qui sert de base au menu

bull Un GtkMenu pour commencer nous nous aurons dun menu Fichier

bull Six GtkMenuItem pour remplacer nos six boutons

Commenccedilons par la creacuteation du menu nous mettons ce code dans un nouveau fichier dont seul la fonction menu_newsera accessible

menucGtkMenuBar menu_new (gpointer user_data) GtkWidget p_menu_bar = NULL

p_menu_bar = gtk_menu_bar_new () return GTK_MENU_BAR (p_menu_bar)

Le paramegravetre user_data nous servira lors de la connexion des callbacks (nous en avons besoin pour les fonctionscb_new et cb_open)

Ensuite nous allons creacuteer notre sous menu Fichier

menuc Menu Fichier

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 35 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

menuc GtkWidget p_menu = NULL GtkWidget p_menu_item = NULL

p_menu = gtk_menu_new () p_menu_item = gtk_menu_item_new_with_mnemonic (_Fichier) gtk_menu_item_set_submenu (GTK_MENU_ITEM (p_menu_item) p_menu) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu_bar) p_menu_item) return GTK_MENU_BAR (p_menu_bar)

Un sous menu est en fait un GtkMenuItem auquel on assigne un GtkMenu Il faut bien sucircr terminer la creacuteation dusous-menu en lajoutant agrave la barre de menu

Pour finir nous creacuteons les eacuteleacutements du menu les GtkItemMenu Il existe plusieurs types deacuteleacutements (comparableaux diffeacuterents types de bouton) pour commencer nous nutiliserons que le type de base Comme cette opeacuteration estreacutepeacutetitive nous allons creacuteer une fonction pour le faire

menucstatic void menu_item_new (GtkMenu p_menu const gchar title GCallback callback gpointer user_data) GtkWidget p_menu_item = NULL

p_menu_item = gtk_menu_item_new_with_mnemonic (title) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu) p_menu_item) g_signal_connect (G_OBJECT (p_menu_item) activate callback user_data)

Pour permettre agrave lutilisateur dacceacuteder aux diffeacuterents eacuteleacutements du menu agrave laide de la touche ltAltgt nous utilisonsdes mneacutemoniques par exemple pour quitter leacutediteur il suffit de faite Alt+F puis Q Et voici le code pour creacuteer nossix eacuteleacutements du menu

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau G_CALLBACK (cb_new) user_data) menu_item_new (GTK_MENU (p_menu) _Ouvrir G_CALLBACK (cb_open) user_data) menu_item_new (GTK_MENU (p_menu) _Enregistrer G_CALLBACK (cb_save) user_data) menu_item_new (GTK_MENU (p_menu) Enregistrer _sous G_CALLBACK (cb_saveas) user_data) menu_item_new (GTK_MENU (p_menu) _Fermer G_CALLBACK (cb_close) user_data) menu_item_new (GTK_MENU (p_menu) _Quitter G_CALLBACK (cb_quit) user_data)

Voilagrave notre menu est creacuteeacute il nous reste plus quagrave linteacutegrer agrave notre fenecirctre

mainc gtk_box_pack_start (GTK_BOX (p_main_box) GTK_WIDGET (menu_new (p_text_view)) FALSE FALSE 0)

Le problegraveme cest que nous avons besoin de passer le GtkTextView lors de la creacuteation du menu (qui est utiliseacute par lesfonctions cb_new et cb_open) or celui-ci est creacuteeacute apregraves le menu (puisque nous creacuteons les widgets dans lordre ougrave ilfaut les inteacutegrer agrave linterface (8) ) nous devons creacuteer le GtkTextView (seul lappel agrave gtk_text_view_new est deacuteplaceacute)

XII-C - Code source

chapitre12zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 36 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIII - Les barres doutils

XIII-A - Aperccedilu

Cliquez pour agrandir

XIII-B - Creacuteation dune barre doutils

La creacuteation dune barre doutils ressemble fort agrave celle dun menu en plus simple puisquil ny a pas de sous menu on creacutee notre barre doutils (gtk_toolbar_new) puis les eacuteleacutements de la barre pour cela on utilise des boutons(gtk_tool_button_new_from_stock) que lon inseacutere dans la barre (gtk_toolbar_insert) Pas conseacutequent notre fichierbarreoutilsc ressemble agrave menuc

barreoutilscinclude ltgtkgtkhgtinclude callbackhinclude barreoutilsh

static void toolbar_item_new (GtkToolbar const gchar GCallback gpointer)

GtkToolbar toolbar_new (gpointer user_data) GtkWidget p_toolbar = NULL

p_toolbar = gtk_toolbar_new () toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_NEW G_CALLBACK (cb_new) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_OPEN G_CALLBACK (cb_open) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE G_CALLBACK (cb_save) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE_AS G_CALLBACK (cb_saveas) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_CLOSE G_CALLBACK (cb_close) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_QUIT G_CALLBACK (cb_quit) user_data) return GTK_TOOLBAR (p_toolbar)

static void toolbar_item_new (GtkToolbar p_toolbar const gchar stock_id GCallback callback gpointer user_data) GtkToolItem p_tool_item = NULL

p_tool_item = gtk_tool_button_new_from_stock (stock_id) g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data) gtk_toolbar_insert (p_toolbar p_tool_item -1)

Le code nest pas complet car lorsque jexeacutecute le programme GTK+ affiche en plus des icocircnes le texte sous lesboutons Pour modifier cela il suffit dajouter une ligne de code

barreoutilsc gtk_toolbar_set_style (GTK_TOOLBAR (p_toolbar) GTK_TOOLBAR_ICONS)

Pourquoi gtk_tool_button_new_from_stock retourne un GtkToolItem et non un GtkWidgetcomme nous avons eacuteteacute habitueacute jusquagrave preacutesent Il sagit dune bizarrerie de GTK+ dontje ne connais pas la raison

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 37 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour anticiper un changement dinterface (dans GTK+ 30 peut ecirctre ) nous aurions pueacutecrire

Gtkwidget p_tool_item = NULL

p_tool_item = GTK_WIDGET (gtk_tool_button_new_from_stock (stock_id))g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data)gtk_toolbar_insert (p_toolbar GTK_TOOL_ITEM (p_tool_item) -1)

XIII-C - Code source

chapitre13zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 38 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIV - Les racourcis clavier

XIV-A - Aperccedilu

Cliquez pour agrandir

XIV-B - Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mneacutemoniques ces derniers permettent dacceacuteder agrave un eacuteleacutementseacutequentiellement alors que les raccourcis appellent une fonction si lutilisateur appuie simultaneacutement sur une ouplusieurs touches (geacuteneacuteralement de la forme ltModificateurgtTouche ougrave Modificateur repreacutesente les touches ShiftAlt et Control) Ce raccourci peut ecirctre attacheacute agrave un eacuteleacutement du menu mais ceci nest pas obligatoire

Les raccourcis sont regroupeacutes en groupe dans un GtkAccelGroup quil faut commencer par creacuteer

raccourciscinclude ltgtkgtkhgtinclude callbackhinclude raccourcish

GtkAccelGroup accel_group_new (gpointer user_data) GtkAccelGroup p_accel_group = NULL

p_accel_group = gtk_accel_group_new () return p_accel_group

Vous commencez agrave avoir lhabitude de cette organisation nous allons donc creacuteer une fonction qui va se chargerdajouter un raccourci au groupe

raccourciscstatic void accelerator_new (GtkAccelGroup p_accel_group const gchar accelerator const gchar accel_path GCallback callback gpointer user_data) guint key GdkModifierType mods GClosure closure = NULL

gtk_accelerator_parse (accelerator ampkey ampmods) closure = g_cclosure_new (callback user_data NULL) gtk_accel_group_connect (p_accel_group key mods GTK_ACCEL_VISIBLE closure) gtk_accel_map_add_entry (accel_path key mods)

La fonction gtk_accelerator_parse permet de deacutecomposer une chaicircne de caractegraveres de la forme ltControlgtF1 ouencore ltAltgtA en numeacutero de touche et modificateur

En plus des touches pour creacuteer un raccourci clavier nous avons besoin dune fonction agrave appeler lorsque lutilisateurappuie sur les touches speacutecifieacutees gtk_accel_group_connect attend une fonction du type GClosure regardons ladocumentation de gobject pour savoir agrave quoi cela correspond

typedef struct

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 8 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

II - Notre premiegravere fenecirctre

II-A - Aperccedilu

II-B - Creacuteation

La fenecirctre principale est repreacutesenteacutee par la classe GtkWindow

La creacuteation dune fenecirctre se fait simplement en appelant le constructeur de cette classe la fonction gtk_window_new

GtkWidget gtk_window_new (GtkWindowType type)

Le seul paramegravetre de cette fonction est le type de fenecirctre souhaiteacute Il ny a que deux possibiliteacutes

bull GTK_WINDOW_TOPLEVEL une fenecirctre classique (cest la base de notre application)

bull GTK_WINDOW_POPUP il sagit dune fenecirctre avec seulement lespace de travail (pas de bordure ni demenu systegraveme)

Cette fonction renvoie un pointeur sur une structure de type GtkWindow (transformer en GtkWidget gracircce aupolymorphisme) qui est lentiteacute qui va nous servir agrave manipuler notre fenecirctre

II-C - Affichage

Si vous essayez deacutecrire un code maintenant vous ne verrez rien pourquoi Tout simplement parce quil faut preacuteciseragrave GTK+ quil faut rendre notre fenecirctre visible gracircce agrave la fonction gtk_widget_show

void gtk_widget_show (GtkWidget widget)

Voici le code qui permet dafficher notre premiegravere fenecirctre

maincinclude ltstdlibhgtinclude ltgtkgtkhgt

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL)

Affichage de la fenetre principale gtk_widget_show (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 9 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Ceux qui se sont essayeacutes agrave la creacuteation dapplications graphiques avec lAPI Windows comprendront la simpliciteacutede ce code

II-D - Destruction

Dans lexemple preacuteceacutedent si vous avez essayeacute de terminer lapplication en fermant la fenecirctre (Alt+F4 ou en cliquantsur la petite croix) vous vous ecirctes peut-ecirctre aperccedilu que lapplication tournait encore en fond cest le mecircme problegravemeque pour le chapitre preacuteceacutedent on ne fait pas appel agrave gtk_main_quit Mais comment appeler cette fonction puisquequune fois gtk_main appeleacutee nous ne pouvons rien faire Cest lagrave quintervient le meacutecanisme des callback A chaqueeacuteveacutenement qui se produit la bibliothegraveque GObject produit un signal si nous souhaitons modifier le comportementpar deacutefaut du signal il suffit de connecter notre fonction callback agrave leacuteveacutenement souhaiteacute

define g_signal_connect(instance detailed_signal c_handler data)

Cette macro permet dintercepter leacuteveacutenement detailed_signal de lobjet instance gracircce agrave la fonction c_handler quidoit ecirctre du type GCallback

void (GCallback) (void)

Les fonctions callback peuvent bien sucircr recevoir des paramegravetres mais leur nature et leur nombre deacutependent ducontexte tout est geacutereacute par la bibliothegraveque GObject Le prototype le plus courant pour une fonction de rappel estle suivant

void callback (GtkWidget p_widget gpointer user_data)

Dont le premier paramegravetre est le widget qui a reccedilu le signal et le second correspond au paramegravetre data de la fonctiong_signal_connect qui nous permet de passer des informations aux fonctions callback Pour finir proprement notreapplication il suffit dintercepter le signal destroy de notre fenecirctre et dy assigner la fonction gtk_main_quit qui neprend pas dargument Voici donc notre premiegravere application fonctionnelle

maincinclude ltstdlibhgtinclude ltgtkgtkhgt

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (gtk_main_quit) NULL)

Affichage de la fenetre principale gtk_widget_show (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

Il est plus courant de creacuteer notre propre fonction de rappel pour quitter le programme ceci permet de libeacuterer lameacutemoire alloueacutee fermer les fichiers ouverts

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 10 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

maincinclude ltstdlibhgtinclude ltgtkgtkhgt

void cb_quit (GtkWidget gpointer)

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (cb_quit) NULL)

Affichage de la fenetre principale gtk_widget_show (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

void cb_quit (GtkWidget p_widget gpointer user_data) gtk_main_quit()

Parametres inutilises (void)p_widget (void)user_data

Le preacutefixe cb_ permet de diffeacuterencier les fonctions callback quil est preacutefeacuterable de regrouper dans un ou plusieursfichiers seacutepareacutes

A la fin de la fonction je transtype les paramegravetres inutiliseacutes pour eacuteviter que moncompilateur mindique des variables non utiliseacutees cest le problegraveme avec les fonctionscallback lAPI nous impose un prototype

II-E - Code source

chapitre2zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 11 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

III - Fermer notre fenecirctre gracircce aux boutons

III-A - Aperccedilu

III-B - Les boutons poussoir

Maintenant que notre programme se termine proprement il est plus convivial de proposer agrave lutilisateur un boutonpour quitter Pour creacuteer un bouton poussoir il existe plusieurs possibiliteacutes

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 premiegravere fonction creacutee un bouton qui peut servir pour contenir nimporte quel autre widget (label image) Si voussouhaitez creacuteer un bouton avec du texte dessus utilisez directement la seconde fonction qui prend en argument letexte agrave afficher Si vous souhaitez ajouter un raccourci clavier (accessible avec la touche Alt) la troisiegraveme fonctionpermet den speacutecifier un en faisant preacuteceacuteder une lettre (geacuteneacuteralement la premiegravere) dun underscore _ (si voussouhaitez afficher le caractegravere _ il faut en mettre deux) Enfin la derniegravere fonction permet dutiliser les Stock Itemsqui sont un ensemble deacuteleacutements preacutedeacutefinis par GTK+ pour les menus et barres doutils Le seul paramegravetre de cettefonction est le nom de leacuteleacutement et GTK+ se charge dafficher licocircne approprieacutee ainsi que le texte suivant la languechoisie et un raccourci

Cest bien sucircr cette derniegravere fonction que nous allons utiliser et ce le plus souvent possible Voici le code pour creacuteerun tel bouton

maincGtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_QUIT)

Pour obtenir tous les types de stocks items disponibles GtkStockItem

Bien sucircr comme pour la fenecirctre si lon veut voir quelque chose il faut demander agrave GTK+ dafficher notre widget

maincgtk_widget_show (p_button)

Mais pas seulement En effet il faut preacuteciser agrave GTK+ ougrave doit ecirctre afficheacute notre bouton Pour cela la classe GtkWindowest deacuteriveacutee de la classe GtkContainer qui est comme son nom le laisse penser un conteneur pour widget Pourajouter un widget il suffit de faire appel agrave la fonction gtk_container_add

void gtk_container_add (GtkContainer container GtkWidget widget)

Le premier paramegravetre de cette fonction est un GtkContainer or nous souhaitons passer notre fenecirctre qui est unGtkWidget pour ne pas avoir de problegravemes il faut utiliser le systegraveme de macro offert par GTK+ pour transtyper notreGtkWidget en GtkContainer (eh oui en C le polymorphisme a ses limites)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 12 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

maincgtk_container_add (GTK_CONTAINER (p_window) p_button)

Ce meacutecanisme de transtypage permet agrave GTK+ de veacuterifier que notre GtkWidget est bien compatible avec lutilisationque lon souhaite en faire En cas deacutechec GTK+ nous preacutevient en affichant un message dans la console

(gtk_boutonexe1044) Gtk-CRITICAL gtk_container_add assertion `GTK_IS_CONTAINER (container) failed

Pour finir il faut connecter notre bouton pour appeler notre fonction cb_quit lorsque lutilisateur clic dessus (ce quicorrespond agrave leacuteveacutenement clicked)

g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_quit) NULL)

Pour eacuteviter dappeler la fonction gtk_widget_show pour tous les widgets de notreapplication on peut se contenter dun seul appel agrave la fonction gtk_widget_show_all quipermet dafficher tous les widgets contenus dans celui passeacute agrave la fonction

maincinclude ltstdlibhgtinclude ltgtkgtkhgtinclude callbackh

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (cb_quit) NULL)

GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_QUIT) gtk_container_add (GTK_CONTAINER (p_window) p_button) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_quit) NULL)

Affichage de la fenetre principale gtk_widget_show_all (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

III-C - Code source

chapitre3zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 13 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IV - Comment afficher plusieurs widgets

IV-A - Aperccedilu

IV-B - Le problegraveme

Dans la partie preacuteceacutedente nous avons reacuteussi agrave afficher un bouton dans la fenecirctre de notre application Si vous avezessayeacute dajouter un second widget GTK+ agrave ducirc vous reacutepondre poliment

(gtk_boxexe492) Gtk-WARNING Attempting to add a widget with typeGtkButton to a GtkWindow but as a GtkBin subclass a GtkWindow can only containone widget at a time it already contains a widget of type GtkButton

Les plus anglophiles dentre vous auront compris que GTK+ naccepte pas lajout un second widget dans notre fenecirctretout simplement parce quil y en a deacutejagrave un et que la sous classe GtkBin (classe megravere de notre GtkWindow) ne peutcontenir quun seul widget

IV-C - La solutions

Pour contourner ce problegraveme il faut commencer par creacuteer un widget qui accepte den contenir plusieurs autrespour ensuite y ajouter tout ce dont nous avons besoin Pour linstant nous utiliserons quun seul widget (il existetrois classes qui permettent ceci) il sagit des GtkBox Il sagit de la meacutethode que jutilise le plus souvent Ce nestpeut-ecirctre pas la plus simple agrave maicirctriser mais elle extrecircmement souple et puissante Elle consiste agrave creacuteer une boicirctepuis agrave y ajouter les widgets les uns apregraves les autres (soit au deacutebut soit agrave la fin) Il existe deux classes heacuteritant deGtkBox les GtkVBox qui empilent les widgets dans le sens vertical et les GtkHBox qui font de mecircme mais dansle sens horizontal Les fonctions pour manipuler ces deux classes sont les mecircmes seule la fonction pour les creacuteerportent un nom diffeacuterent

GtkWidget gtk_vbox_new (gboolean homogeneous gint spacing)GtkWidget gtk_hbox_new (gboolean homogeneous gint spacing)

Le paramegravetre homogeneous permet de reacuteserver pour chaque widget une zone de taille identique (zone que le widgetnest pas obligeacute de remplir) et spacing permet dajouter une bordure en pixels (espacement autour de la GtkBox)Ensuite il suffit dajouter les diffeacuterents widgets gracircce aux fonctions

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)

Qui ajoutent reacuteciproquement le widget child au deacutebut et agrave la fin de box Le paramegravetre expand permet au widget davoirle plus de place possible (si le paramegravetre homogeneous vaut TRUE cette option a aucun effet) Si plusieurs widgetont ce paramegravetre agrave TRUE ils se partagent de faccedilon eacutegale lespace Loption fill permet au widget de remplir toutlespace qui lui ait reacuteserveacute

Pour reacuteellement comprendre linfluence de ces paramegravetres il faut faire des tests en modifiant un agrave un chaqueparamegravetre et observer les effets dun redimentionnement de la fenecirctre principale

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 14 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Le plus gecircnant avec cette meacutethode cest quil faut jongler entre les GtkHBox et les GtkVBox en les imbriquant pourobtenir le reacutesultat souhaiter nheacutesitez pas agrave utiliser une feuille et un crayon )

Pour en revenir agrave notre eacutediteur de texte nous allons preacuteparer notre application agrave contenir les futurs widgetsNous utilisons un GtkVBox pour lensemble des widgets (il sagit de la boicircte principale qui pourra contenir dautresGtkContainer selon nos besoins)

maincinclude ltstdlibhgtinclude ltgtkgtkhgtinclude callbackh

int main (int argc char argv) GtkWidget p_window = NULL GtkWidget p_main_box = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (cb_quit) NULL)

Creation du conteneur principal p_main_box = gtk_vbox_new (FALSE 0) gtk_container_add (GTK_CONTAINER (p_window) p_main_box)

Creation du bouton Quitter GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_QUIT) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_quit) NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_button FALSE FALSE 0)

Affichage de la fenetre principale gtk_widget_show_all (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

IV-D - Code source

chapitre4zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 15 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

V - Afficher le contenue dun fichier

V-A - Aperccedilu

Cliquez pour agrandir

V-B - Saisir du texte

Les choses seacuterieuses vont commencer il sagit de mettre en place le widget qui va nous permettre dafficher etdeacutediter du texte Il sagit de la classe GtkTextView Gracircce agrave GTK+ la mise en place est toujours aussi simple

mainc GtkWidget p_text_view = NULL Creation de la zone de texte p_text_view = gtk_text_view_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_text_view TRUE TRUE 0)

Comme il sagit de la partie centrale de notre application nous demandons agrave ce quelle prenne le plus de placepossible (gracircce agrave la fonction gtk_box_pack_start)

Puisque nous voulons afficher les boutons en dessous de la zone de texte il faut ajouter ce morceau de code avantcelui creacuteant le bouton

V-C - Ouvrir un fichier

Maintenant nous avons une belle zone de texte il faut la remplir avec le contenu dun fichier Pour ce faire nousallons commencer par ajouter un bouton ouvrir

mainc Creation du bouton Ouvrir GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_OPEN) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_open) p_text_view) gtk_box_pack_start (GTK_BOX (p_main_box) p_button FALSE FALSE 0)

Si vous exeacutecutez le programme maintenant (3) vous remarquerez que les boutons sont ajouteacutes les uns en dessousdes autres ce qui diminue la zone de saisie (avec deux boutons ce nest pas gecircnant mais au bout dune dizaineccedila risque decirctre probleacutematique) Pour pallier ce problegraveme nous allons utiliser un nouveau style de GtkBox lesGtkButtonBox qui sont preacutevus pour contenir des boutons (ccedila tombe plutocirct bien D) Donc pour eacuteviter de diminuerla zone de saisie et comme nous avons de la place en largueur nous allons utiliser un GtkHButtonBox qui va ecirctreinclus dans la p_main_box Voici les modifications agrave effectuer

mainc GtkWidget p_button_box = NULL Creation du conteneur pour les boutons p_button_box = gtk_hbutton_box_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_button_box FALSE FALSE 0)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 16 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc gtk_box_pack_start (GTK_BOX (p_button_box) p_button FALSE FALSE 0) gtk_box_pack_start (GTK_BOX (p_button_box) p_button FALSE FALSE 0)

Maintenant il nous reste plus quagrave creacuteer la fonction cb_open dans le fichier callbackc pour linstant nous nouscontenterons douvrir toujours le mecircme fichier nous verrons plus tard comment laisser le choix agrave lutilisateur

callbackcdefine DEFAULT_FILE mainc

void cb_open (GtkWidget p_widget gpointer user_data) open_file (DEFAULT_FILE GTK_TEXT_VIEW (user_data))

Parametre inutilise (void)p_widget

Vous aurez compris que lon va deacuteleacuteguer tout le travail agrave la fonction open_file qui devra ouvrir le fichier dont le nomest passeacute en premier paramegravetre pour lafficher dans le GktTextView

Jai fait ce choix pour deux raisons le code dune fonction callback peut ecirctre tregraves conseacutequent (surtout si lon souhaitequelle affiche une boicircte de dialogue) et aussi parce que cb_open nest peut ecirctre pas la seule fonction agrave copierun fichier dans un GtkTextView (par exemple lors de la creacuteation dun nouveau fichier lon peut vouloir copier unsquelette de fichier)

Pour copier notre fichier plutocirct que dutiliser la fonction fgets nous allons nous servir de la glib (4) qui proposela fonction

gboolean g_file_get_contents (const gchar filename gchar contents gsize length GError error)

Qui nous renvoit le contenu du fichier nommeacute filename dans le tampon contents Il est possible de reacutecupeacuterer lenombre de caractegraveres copieacutes et retourne TRUE en cas de succegraves sinon FALSE et dans ce cas une structure de typeGError est creacutee pour en savoir plus sur le type derreur rencontreacute

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView else print_warning (Impossible douvrir le fichier sn file_name)

Je pense quun certain nombre dexplications simpose (surtout si je vais trop vite nheacutesitez pas agrave marrecircter )

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 17 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

bull g_return_if_fail est une macro qui peut ecirctre compareacutee agrave assert sauf quelle se contente de sortir de la fonctionsi lexpression passeacutee en paramegravetre est fausse Cest une meacutethode pratique pour veacuterifier la validiteacute desparamegravetres (si la fonction doit retourne une valeur utiliseacute plutocirct g_return_val_if_fail qui prend un secondparamegravetre la valeur agrave retourner)

bull Ensuite on essaie de reacutecupeacuterer le contenu de notre fichier

bull Si cela eacutechoue nous le signalons agrave lutilisateur agrave laide de la fonction print_warning

bull Le type gchar est une redeacutefinition du type char par la glib (il en va de mecircme pour tous les autres types du C)privileacutegiez ces types lorsque vous utilisez des fonctions de cette bibliothegraveques

Mais quest-ce donc cette fonction print_warning Cest une fonction que nous allons creacuteer semblable agrave printf quisignalera agrave lutilisateur quune erreur non critique est survenue Comme nous navons pas encore abordeacute les boicirctesde dialogue pour afficher un message il sagira pour linstant dune simple redeacutefinition de printf Pendant que noussommes dans laffichage des messages nous allons aussi creacuteer deux fonctions print_info et print_error qui vontrespectivement afficher un message dinformation et un message derreur critique (ce qui entraicircne la terminaison duprogramme) tout ceci dans un nouveau fichier errorc

errorhifndef H_ERRORdefine H_ERROR

void print_info (char )void print_warning (char )void print_error (char )

endif not H_ERROR

errorcinclude ltstdarghgtinclude ltstdiohgtinclude ltstdlibhgtinclude errorh

void print_info (char format ) va_list va

va_start (va format) printf (Information ) vprintf (format va) printf (n)

void print_warning (char format ) va_list va

va_start (va format) fprintf (stderr Erreur ) vfprintf (stderr format va) fprintf (stderr n)

void print_error (char format ) va_list va

va_start (va format) fprintf (stderr Erreur fatale ) vfprintf (stderr format va) fprintf (stderr n) exit (EXIT_FAILURE)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 18 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

Pour en finir avec louverture dun fichier il nous reste agrave copier contents dans le GtkTextView En fait le GtkTextViewne gegravere que la forme pour modifier le contenu il faut passer par les GtkTextBuffer Commenccedilons donc par reacutecupeacutererce fameux GtkTextBuffer

callbackc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (p_text_view)

Et pour finir on utilise la fonction

void gtk_text_buffer_insert (GtkTextBuffer buffer GtkTextIter iter const gchar text gint len)

Reacutecapitulons buffer est le GtkTextBuffer que lon vient de reacutecupeacuterer text cest le texte agrave afficher et len la taille dece dernier (ou -1 sil sagit dune chaicircne de caractegraveres au sens du langage C)

Mais quest-ce donc ce GtkTextIter On peut voir cela comme un curseur virtuel qui indique la position agrave laquelleeffectuer linsertion de texte dans le GtkTextBuffer (5) Allons voir ce que la documentation peut nous apprendreagrave leur sujet (6)

typedef struct GtkTextIter is an opaque datatype ignore all these fields Initialize the iter with gtk_text_buffer_get_iter_ functions GtkTextIter

Voilagrave on a notre solution suffit de rechercher les fonctions commenccedilant par gtk_text_buffer_get_iter_ voici la liste

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)

La fonction gtk_text_buffer_get_iter_at_line fait parfaitement laffaire

callbackc GtkTextIter iter

gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1)

Cependant si vous ne voulez pas avoir de problegravemes avec le codage des caractegraveres il vaut mieux convertir le codagelocal vers utf8 Voici le reacutesultat final

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 19 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gchar utf8 = NULL GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_text_buffer_insert (p_text_buffer ampiter utf8 -1) g_free (utf8) utf8 = NULL

V-D - La petite touche finale

Pour finir cette laborieuse partie sur une petite touche estheacutetique nous allons demander agrave GTK+ de nous lancerlapplication en plein eacutecran Pour se faire il suffit dajouter lors de la creacuteation de la fenecirctre principale

maincgtk_window_maximize (GTK_WINDOW (p_window))

On peut mecircme se permettre une pointe dexcentriciteacute en modifiant le titre de notre fenecirctre

maincgtk_window_set_title (GTK_WINDOW (p_window) Editeur de texte en GTK+)

V-E - Code source

chapitre5zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 20 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VI - Choisir un fichier

VI-A - Aperccedilu

Cliquez pour agrandir

VI-B - Utilisation dun GtkFileChooserFile

Jusquagrave preacutesent lutilisateur navait pas le choix quant au fichier agrave ouvrir heureusement GTK+ vient agrave notre aide gracircceau widget GtkFileChooserFile qui est tout simplement une boicircte de dialogue qui propose agrave lutilisateur de seacutelectionnerun fichier dans son arborescence disque

Commenccedilons par creacuteer notre boicircte de dialogue dans la fonction cb_open

callbackcvoid cb_open (GtkWidget p_widget gpointer user_data) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Ouvrir un fichier NULL GTK_FILE_CHOOSER_ACTION_OPEN GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_OPEN GTK_RESPONSE_ACCEPT NULL)

Cette fonction neacutecessite le titre de la boicircte de dialogue une fenecirctre parente le type daction (ici on souhaite ouvrir unfichier GTK+ autorisera lutilisateur agrave seacutelectionner uniquement les fichiers existants) Pour finir il sagit dun couple devaleurs GTK_STOCK_ITEMGTK_STOCK_RESPONSE qui permet de creacuteer un bouton utilisant le stock ID speacutecifieacuteet lorsque celui-ci est cliqueacute la fonction servant agrave lancer la boicircte de dialogue retournera le reacuteponse ID correspondantIl existe une seacuterie de valeurs deacutefinies par GTK+ quil est conseilleacute dutiliser

typedef enum GTK returns this if a response widget has no response_id or if the dialog gets programmatically hidden or destroyed GTK_RESPONSE_NONE = -1

GTK wont return these unless you pass them in as the response for an action widget They are for your convenience GTK_RESPONSE_REJECT = -2 GTK_RESPONSE_ACCEPT = -3

If the dialog is deleted GTK_RESPONSE_DELETE_EVENT = -4

These are returned from GTK dialogs and you can also use them yourself if you like GTK_RESPONSE_OK = -5 GTK_RESPONSE_CANCEL = -6 GTK_RESPONSE_CLOSE = -7 GTK_RESPONSE_YES = -8

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 21 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GTK_RESPONSE_NO = -9 GTK_RESPONSE_APPLY = -10 GTK_RESPONSE_HELP = -11 GtkResponseType

Nous indiquons la fin des couples stock idreacuteponse id avec la valeur NULL

Une fois la boicircte de dialogue creacuteee on demande agrave GTK+ de lafficher gracircce agrave la fonction gtk_dialog_run puis onreacutecupegravere sa valeur de retour qui correspond au bouton cliqueacute par lutilisateur

callbackc if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

Ici ce qui nous inteacuteresse cest lorsque que lutilisateur clique sur le bouton ouvrir (donc gtk_dialog_run renvoieGTK_RESPONSE_ACCEPT) dans ce cas il nous suffit de reacutecupeacuterer le nom du fichier seacutelectionneacute puis de louvrir

callbackc gchar file_name = NULL

file_name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) open_file (file_name GTK_TEXT_VIEW (user_data)) g_free (file_name) file_name = NULL

Pour finir dans tous les cas on noublie pas de deacutetruire la boicircte de dialogue

callbackc gtk_widget_destroy (p_dialog)

Et voilagrave le travail lutilisateur peut ouvrir le fichier quil souhaite

VI-C - Code source

chapitre6zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 22 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VII - Interlude

Avant daller plus loin dans lameacutelioration de linterface de notre eacutediteur il est neacutecessaire de modifier sonfonctionnement interne (ne vous inquieacutetez je nai pas dit chambouler) en effet souvenez-vous dans lintroduction jaieacutevoqueacute la possibiliteacutes douvrir plusieurs documents gracircce agrave un systegraveme donglets Pour cela il faut sauvegarder lesproprieacuteteacutes de chaque document ouvert Pris agrave temps ce genre de modification nest pas trop lourde mais si nousattendons cela risque de devenir un vrai casse tecircte

Pour cela nous allons utiliser une structure de donneacutee pour chaque document ouvert qui devra garder en meacutemoirele chemin complet du fichier (ou NULL si le document nest pas encore sauvegarder) sil agrave eacutetait modifier depuis laderniegravere sauvegarde et le GtkTextView qui sert agrave son affichage Voici donc la structure qui va nous servir

documenthtypedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

Sachant que nous serons ameneacute agrave stocker plusieurs occurrences de cette structure il serait bon de reacutefleacutechir degravesmaintenant agrave la structure de donneacutee agrave utiliser pour les stocker La premiegravere ideacutee qui vient agrave lesprit est un tableaualloueacute dynamiquement cependant lutilisateur peut souhaiter fermer un document qui se trouve au milieu on estalors obligeacute de deacutecaler toutes les cellules en amont Dans ce cas il parait naturel dutiliser une liste chaicircneacutee Parchance la glib propose une bibliothegraveque de gestion des listes chaicircneacutees cela nous fera gagner du temps le momentvenu Pour linstant on se contente de creacuteer une structure de donneacutees qui contiendra tous les documents ouverts(stockeacutee dans une GList) et un pointeur sur le document actif (actuellement comme nous navons quun documentouvert en mecircme temps on manipulera uniquement ce pointeur)

documenthtypedef struct GList tous document_t actif docs_t

Maintenant se pose le problegraveme de savoir comment transmettre cette structure On pourrait se servir du paramegravetreuser_data preacutesent dans toutes les fonctions callback mais certaines fonctions utilise deacutejagrave ce paramegravetre (la fonctioncb_open par exemple) il faudrait creacuteer un champs suppleacutementaire dans notre structure documents_s Une solutionplus simple est de creacuteer une variable globale agrave lensemble du programme Ceux qui passe reacuteguliegraverement sur le forumC savent que cest fortement deacuteconseilleacute mais ici nous nous trouvons dans lune des rares exceptions agrave la regravegle Detoute faccedilon cela revient au mecircme que de passer ladresse de notre structure agrave toutes les fonctions callback Nousdeacutefinissons donc un nouveau fichier den-tecircte

documenthifndef H_DOCUMENTdefine H_DOCUMENT

include ltgtkgtkhgt

typedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 23 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

documenthtypedef struct GList tous document_t actif docs_t

extern docs_t docs

endif not H_DOCUMENT

Et dans le fichier mainc

maincinclude documenth

docs_t docs = NULL NULL

Pour linstant la seule fonction qui modifie leacutetat dun document est la fonction open_file il faut donc inclure documenthdans callbackc et modifier leacutegegraverement la fonction pour enregistrer le document ouvert

callbackc if (g_file_get_contents (file_name ampcontents NULL NULL)) Pour linstant il faut allouer la memoire par la suite on modifira simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = g_strdup (file_name) Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = p_text_view Le document vient detre ouvert il nest donc pas modifie docsactif-gtsauve = TRUE

Ne soyez pas choqueacute si je ne teste pas le retour de la fonction g_malloc pour veacuterifier quilnest pas NULL En effet cette derniegravere met fin agrave lapplication si lallocation eacutechoue

VII-A - Code source

chapitre7zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 24 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VIII - Sauvegarder les modification

VIII-A - Aperccedilu

Cliquez pour agrandir

VIII-B - Enregistrer

Avant de pouvoir sauvegarder un document il faut quil soit modifieacute Comment savoir que le contenu du fichier a eacuteteacutemodifier Gracircce au signal changed du GtkTextBuffer que nous interceptons gracircce agrave la fonction cb_modifie

mainc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (p_text_view)) g_signal_connect (G_OBJECT (p_text_buffer) changed G_CALLBACK (cb_modifie) NULL)

Cette derniegravere modifie simplement le champ sauve du document

callbackcvoid cb_modifie (GtkWidget p_widget gpointer user_data) if (docsactif) docsactif-gtsauve = FALSE

Pour la sauvegarde il faut distinguer deux cas soit il sagit de la premiegravere sauvegarde du fichier il faut alors demanderle nom du fichier agrave lutilisateur (cela ressemble fortement agrave louverture dun fichier) soit le fichier est deacutejagrave preacutesent surle disque il suffit de remplacer son contenu par celui du GtkTextViewer Nous avons convenu quun fichier qui neacutetaitpas encore enregistreacute avait sa proprieacuteteacute chemin agrave NULL

Bien sucircr cela na lieu que si un fichier est ouvert et quil a eacuteteacute modifieacute depuis sa derniegravere sauvegarde

callbackcvoid cb_save (GtkWidget p_widget gpointer user_data) if (docsactif) if (docsactif-gtsauve) Le fichier na pas encore ete enregistre if (docsactif-gtchemin) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Sauvegarder le fichier NULL GTK_FILE_CHOOSER_ACTION_SAVE GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_SAVE GTK_RESPONSE_ACCEPT NULL) if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 25 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc docsactif-gtchemin = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) gtk_widget_destroy (p_dialog) Soit le fichier a deja ete enregistre soit lutilisateur vient de nous fournir son nouvel enplacement on peut donc lenregistrer if (docsactif-gtchemin) else print_warning (Aucun document ouvert)

Il nous reste plus quagrave reacutecupeacuterer le contenu du GtkTextViewer et le copier dans le fichier chemin sans oublier dereconvertir le texte dans le codage local

callbackc FILE fichier = NULL

fichier = fopen (docsactif-gtchemin w) if (fichier) gchar contents = NULL gchar locale = NULL GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) contents = gtk_text_buffer_get_text (p_text_buffer ampstart ampend FALSE) locale = g_locale_from_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL fprintf (fichier s locale) g_free (locale) locale = NULL fclose (fichier) fichier = NULL docsactif-gtsauve = TRUE else print_warning (Impossible de sauvegarder le fichier s docsactif-gtchemin)

Le dernier paramegravetre de la fonction gtk_text_buffer_get_text est mis agrave FALSE car nous ne voulons pas enregistrerles caractegraveres invisibles preacutesent dans le GtkTextBuffer Ces caractegraveres servent agrave mettre en forme le texte (taillecouleur) nous pourrions creacuteer un nouveau format de fichier pour enregistrer la mise en forme

VIII-C - Enregistrer sous

Pour enregistrer notre document sous un autre nom il suffit de faire croire agrave cb_save que le document na pas encoreeacutetait enregistreacute tout simplement en changeant chemin agrave NULL et sauve agrave FALSE

callbackcvoid cb_saveas (GtkWidget p_widget gpointer user_data)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 26 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (docsactif) document_t tmp = docsactif

docsactif-gtchemin = NULL docsactif-gtsauve = FALSE cb_save (p_widget user_data) if (docsactif-gtsauve) (docsactif) = tmp else print_warning (Aucun document ouvert)

Il ne faut pas oublier que lutilisateur peut annuler lenregistrement de ce fait nous sauvegardons leacutetat du documentet si la sauvegarde na pas eu lieu on le restaure

VIII-D - Code source

chapitre8zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 27 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IX - Creacuteer un nouveau document

IX-A - Aperccedilu

Cliquez pour agrandir

IX-B - Nouveau fichier

Maintenant que lutilisateur peut ouvrir et fermer un fichier il est inteacuteressant de lui donner la possibiliteacute den creacuteerun nouveau Je ne reviens pas sur la creacuteation du bouton (ccedila devrait deacutejagrave ecirctre fait D) passons directement agrave lafonction cb_new

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) Pour linstant il faut allouer la memoire par la suite on modifiera simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = NULL Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = GTK_TEXT_VIEW (user_data) Le document vient detre creer il nest donc pas modifie docsactif-gtsauve = TRUE gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Je ne sais pas vous mais pour ma part jai fait un copiercoller de la fonction open_file Et oui ouvrir un document peutse reacutesumer agrave creacuteer un document vide puis remplir le GtkTextView avec le fichier souhaiteacute On peut donc simplifiernotre fonction open_file ainsi

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

cb_new (NULL p_text_view) gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE) p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1) Nous sommes obliges de remetre sauve a TRUE car linsertion du contenu du fichier dans le GtkTextView a appele cb_modfie docsactif-gtsauve = TRUE else print_warning (Impossible douvrir le fichier sn file_name)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 28 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc

Cest beau la factorisation du code Par contre nous sommes obligeacutes de remettre sauve agrave TRUE car nous avonsmodifieacute le GtkTextBuffer

IX-C - Code source

chapitre9zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 29 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

X - Fermer

X-A - Aperccedilu

Cliquez pour agrandir

X-B - Fermer un fichier

Maintenant que nous allouons de la meacutemoire il faut la libeacuterer agrave un endroit Logiquement cela va ecirctre fait agrave la fermeturedu document en guise dexercice je vous laisse creacuteer le bouton dans notre boicircte agrave bouton

Allez je vous aide le stock id correspondant est GTK_STOCK_CLOSE

Voilagrave maintenant si tout cest bien passeacute vous devriez ecirctre arriveacute dans le fichier callbackc avec quelque choseressemblant agrave

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data)

Lorsque lon ferme un document il faut vider le GtkTextView (avec les onglets on se contentera de le supprimer)pour cela il faut reacutecupeacuterer le deacutebut et la fin du GtkTextBuffer et demander agrave GTK+ de supprimer tout ce qui ce trouveentre les deux iteacuterateurs

callbackc Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) gtk_text_buffer_delete (p_text_buffer ampstart ampend) else print_warning (Aucun document ouvert)

Bien sucircr il ne faut pas oublier de libeacuterer la meacutemoire

callbackc g_free (docsactif-gtchemin) docsactif-gtchemin = NULL docsactif-gtp_text_view = NULL g_free (docsactif) docsactif = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 30 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour symboliser la fermeture dun document nous deacutesactivons le GtkTextView lors de la fermeture (ne pas oublierde le faire aussi dans mainc)

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) FALSE)

Et nous le reacuteactivons lors de louverture si celle si reacuteussie

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Lorsque lutilisateur quitte lapplication il faut bien sucircr fermer le document sil y en a un ouvert

void cb_quit (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data) gtk_main_quit()

Et aussi lorsquil creacuteeacute un nouveau document (et par conseacutequent lorsquil ouvre un fichier puisque lon fait appel agravecb_new)

void cb_new (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data)

X-C - Enregistrer avant de fermer

Si le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde geacuteneacuteralement le programme le signale agrave lutilisateur etlui propose de sauvegarder ou dannuler la fermeture Pour se faire nous devons modifier la fonction cb_close avantde fermer le document nous allons afficher une boicircte de dialogue

Pour creacuteer une boicircte de dialogue simplement il existe la classe GtkDialog et comme nous avons besoin de boutons(pour que lutilisateur fasse son choix) nous allons creacuteer notre boicircte avec la fonction

GtkWidget gtk_dialog_new_with_buttons (const gchar title GtkWindow parent GtkDialogFlags flags const gchar first_button_text )

Nous retrouvons les mecircmes options que pour le GtkFileChooserDialog mis agrave part option du type GtkDialogFlags

typedef enum GTK_DIALOG_MODAL = 1 ltlt 0 appel gtk_window_set_modal (win TRUE) GTK_DIALOG_DESTROY_WITH_PARENT = 1 ltlt 1 appel gtk_window_set_destroy_with_parent () GTK_DIALOG_NO_SEPARATOR = 1 ltlt 2 Pas de barre de separation au dessus des boutons GtkDialogFlags

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 31 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Nous nous contenterons de rendre notre fenecirctre modale (7)

Pour avoir accegraves agrave notre fenecirctre principale nous ajoutons un champs p_main_window agrave notre structure globaledocs_t que nous initialisons dans la fonction main

mainc docsp_main_window = GTK_WINDOW (p_window)

Il nous reste plus qua creacuteer notre boicircte de dialogue avec trois boutons Oui Non Annuler

callbackc if (docsactif-gtsauve) GtkWidget p_dialog = NULL

p_dialog = gtk_dialog_new_with_buttons (Sauvegarder docsp_main_window GTK_DIALOG_MODAL GTK_STOCK_YES GTK_RESPONSE_YES GTK_STOCK_NO GTK_RESPONSE_NO GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL NULL)

Nous obtenons donc une structure de type GtkDialog

typedef struct GtkWidget vbox GtkWidget action_area GtkDialog

Nous remarquons que cette structure contient deux membres qui permettent dacceacuteder agrave une GtkBox ougrave nous allonsajouter le contenu de la fenecirctre et agrave la partie contenant les boutons

Ensuite la construction de la fenecirctre est identique agrave celle de la fenecirctre principale ici nous nous contenterons dajouterun GtkLabel

callbackc GtkWidget p_label = NULL p_label = gtk_label_new (Voulez-vous sauvegarder les modifications ) gtk_box_pack_start (GTK_BOX (GTK_DIALOG (p_dialog)-gtvbox) p_label TRUE TRUE 0)

Une fois notre fenecirctre precircte il suffit de faire appel agrave la fonction gtk_dialog_run qui va afficher notre GtkDialog et nousretourner le reacuteponse id correspondant au bouton cliqueacute par lutilisateur

callbackc switch (gtk_dialog_run (GTK_DIALOG (p_dialog))) case GTK_RESPONSE_YES cb_save (p_widget user_data) break case GTK_RESPONSE_NO break case GTK_RESPONSE_CANCEL gtk_widget_destroy (p_dialog) return break

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 32 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc gtk_widget_destroy (p_dialog)

Si lutilisateur clique sur non on ne fait rien (le document sera simplement fermeacute) sur oui on enregistre avant defermer et pour finir sil annule on quitte la fonction

X-D - Code source

chapitre10zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 33 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XI - Les barres de deacutefilement

XI-A - Aperccedilu

Cliquez pour agrandir

XI-B - Ajouter des barres de deacutefilement

Apregraves le dernier chapitre quelque peu laborieux voici une partie plus simple mais qui va rendre notre applicationplus pratique En effet si vous avez essayeacute douvrir un fichier de grande taille vous avez pu remarquer que pourpouvoir lire la fin du fichier il fallait utiliser les touches du clavier pas tregraves convivial

Pour rendre la navigation plus aiseacutee on utilise des barres de deacutefilement

mainc GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_scrolled_window TRUE TRUE 0)

Creation de la zone de texte gtk_container_add (GTK_CONTAINER (p_scrolled_window) p_text_view)

Le constructeur de notre GtkScrolledWindow prend en argument deux GtkAdjustment qui permettent de deacutefinirdiffeacuterentes proprieacuteteacutes de la barre de deacutefilement (taille dune page la position de deacutepart) nous laissons GTK+ faireen passant NULL

Cest un bon deacutebut mais estheacutetiquement on peut faire mieux mecircme sil nest pas utile davoir une barre de deacutefilementelle est quand mecircme afficheacutee On peut demander agrave GTK+ de les afficher que si cela est neacutecessaire

mainc gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC)

En fait nous avons de la chance car la classe GtkTextView fait partie des widget qui supporte de faccedilon native les barresde deacutefilement Comment le savoir Ce genre de widget possegravede une ou deux proprieacuteteacutes de type GtkAdjustment (unepour la barre verticale lautre pour la barre horizontale) Actuellement seulement trois classes en sont capables lesGtkTextView les GtkTreeView et les GtkLayout

Comment faire pour les autres widgets Il faut passer par une classe adaptateur GtkViewport afin de creacuteer lesGtkAdjustment

XI-C - Code source

chapitre11zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 34 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XII - Les menus

XII-A - Aperccedilu

Cliquez pour agrandir

XII-B - Creacuteation du menu

Pour simplifier nous avons utiliseacute des boutons pour permettre agrave lutilisateur de creacuteer un document ouvrir un fichierMais il est plus courant dutiliser un menu pour afficher ces options GTK+ propose trois maniegraveres de creacuteer un menu

bull GtkItemFactory cette meacutethode est obsolegravete depuis la version 24 de GTK+

bull GtkUIManager cest ce quon appel une usine agrave gaz pour en savoir plus vous pouvez vous reporter aututoriel Utilisation de GtkUIManager

bull GtkMenu cest ce widget que nous allons eacutetudier il permet de creacuteer un menu manuellement (agrave lopposeacute deGtkUIManager)

Un menu selon GTK+ est composeacute de plusieurs eacuteleacutements

bull GtkMenuBar la barre de menu elle-mecircme

bull GtkMenu la partie deacuteroulante qui contient les diffeacuterents eacuteleacutements

bull GtkMenuItem cest sur ce widget que lutilisateur clique pour lancer une action

Pour commencer faisons linventaire de ce que nous avons besoin

bull Un GtkMenuBar qui sert de base au menu

bull Un GtkMenu pour commencer nous nous aurons dun menu Fichier

bull Six GtkMenuItem pour remplacer nos six boutons

Commenccedilons par la creacuteation du menu nous mettons ce code dans un nouveau fichier dont seul la fonction menu_newsera accessible

menucGtkMenuBar menu_new (gpointer user_data) GtkWidget p_menu_bar = NULL

p_menu_bar = gtk_menu_bar_new () return GTK_MENU_BAR (p_menu_bar)

Le paramegravetre user_data nous servira lors de la connexion des callbacks (nous en avons besoin pour les fonctionscb_new et cb_open)

Ensuite nous allons creacuteer notre sous menu Fichier

menuc Menu Fichier

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 35 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

menuc GtkWidget p_menu = NULL GtkWidget p_menu_item = NULL

p_menu = gtk_menu_new () p_menu_item = gtk_menu_item_new_with_mnemonic (_Fichier) gtk_menu_item_set_submenu (GTK_MENU_ITEM (p_menu_item) p_menu) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu_bar) p_menu_item) return GTK_MENU_BAR (p_menu_bar)

Un sous menu est en fait un GtkMenuItem auquel on assigne un GtkMenu Il faut bien sucircr terminer la creacuteation dusous-menu en lajoutant agrave la barre de menu

Pour finir nous creacuteons les eacuteleacutements du menu les GtkItemMenu Il existe plusieurs types deacuteleacutements (comparableaux diffeacuterents types de bouton) pour commencer nous nutiliserons que le type de base Comme cette opeacuteration estreacutepeacutetitive nous allons creacuteer une fonction pour le faire

menucstatic void menu_item_new (GtkMenu p_menu const gchar title GCallback callback gpointer user_data) GtkWidget p_menu_item = NULL

p_menu_item = gtk_menu_item_new_with_mnemonic (title) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu) p_menu_item) g_signal_connect (G_OBJECT (p_menu_item) activate callback user_data)

Pour permettre agrave lutilisateur dacceacuteder aux diffeacuterents eacuteleacutements du menu agrave laide de la touche ltAltgt nous utilisonsdes mneacutemoniques par exemple pour quitter leacutediteur il suffit de faite Alt+F puis Q Et voici le code pour creacuteer nossix eacuteleacutements du menu

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau G_CALLBACK (cb_new) user_data) menu_item_new (GTK_MENU (p_menu) _Ouvrir G_CALLBACK (cb_open) user_data) menu_item_new (GTK_MENU (p_menu) _Enregistrer G_CALLBACK (cb_save) user_data) menu_item_new (GTK_MENU (p_menu) Enregistrer _sous G_CALLBACK (cb_saveas) user_data) menu_item_new (GTK_MENU (p_menu) _Fermer G_CALLBACK (cb_close) user_data) menu_item_new (GTK_MENU (p_menu) _Quitter G_CALLBACK (cb_quit) user_data)

Voilagrave notre menu est creacuteeacute il nous reste plus quagrave linteacutegrer agrave notre fenecirctre

mainc gtk_box_pack_start (GTK_BOX (p_main_box) GTK_WIDGET (menu_new (p_text_view)) FALSE FALSE 0)

Le problegraveme cest que nous avons besoin de passer le GtkTextView lors de la creacuteation du menu (qui est utiliseacute par lesfonctions cb_new et cb_open) or celui-ci est creacuteeacute apregraves le menu (puisque nous creacuteons les widgets dans lordre ougrave ilfaut les inteacutegrer agrave linterface (8) ) nous devons creacuteer le GtkTextView (seul lappel agrave gtk_text_view_new est deacuteplaceacute)

XII-C - Code source

chapitre12zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 36 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIII - Les barres doutils

XIII-A - Aperccedilu

Cliquez pour agrandir

XIII-B - Creacuteation dune barre doutils

La creacuteation dune barre doutils ressemble fort agrave celle dun menu en plus simple puisquil ny a pas de sous menu on creacutee notre barre doutils (gtk_toolbar_new) puis les eacuteleacutements de la barre pour cela on utilise des boutons(gtk_tool_button_new_from_stock) que lon inseacutere dans la barre (gtk_toolbar_insert) Pas conseacutequent notre fichierbarreoutilsc ressemble agrave menuc

barreoutilscinclude ltgtkgtkhgtinclude callbackhinclude barreoutilsh

static void toolbar_item_new (GtkToolbar const gchar GCallback gpointer)

GtkToolbar toolbar_new (gpointer user_data) GtkWidget p_toolbar = NULL

p_toolbar = gtk_toolbar_new () toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_NEW G_CALLBACK (cb_new) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_OPEN G_CALLBACK (cb_open) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE G_CALLBACK (cb_save) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE_AS G_CALLBACK (cb_saveas) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_CLOSE G_CALLBACK (cb_close) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_QUIT G_CALLBACK (cb_quit) user_data) return GTK_TOOLBAR (p_toolbar)

static void toolbar_item_new (GtkToolbar p_toolbar const gchar stock_id GCallback callback gpointer user_data) GtkToolItem p_tool_item = NULL

p_tool_item = gtk_tool_button_new_from_stock (stock_id) g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data) gtk_toolbar_insert (p_toolbar p_tool_item -1)

Le code nest pas complet car lorsque jexeacutecute le programme GTK+ affiche en plus des icocircnes le texte sous lesboutons Pour modifier cela il suffit dajouter une ligne de code

barreoutilsc gtk_toolbar_set_style (GTK_TOOLBAR (p_toolbar) GTK_TOOLBAR_ICONS)

Pourquoi gtk_tool_button_new_from_stock retourne un GtkToolItem et non un GtkWidgetcomme nous avons eacuteteacute habitueacute jusquagrave preacutesent Il sagit dune bizarrerie de GTK+ dontje ne connais pas la raison

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 37 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour anticiper un changement dinterface (dans GTK+ 30 peut ecirctre ) nous aurions pueacutecrire

Gtkwidget p_tool_item = NULL

p_tool_item = GTK_WIDGET (gtk_tool_button_new_from_stock (stock_id))g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data)gtk_toolbar_insert (p_toolbar GTK_TOOL_ITEM (p_tool_item) -1)

XIII-C - Code source

chapitre13zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 38 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIV - Les racourcis clavier

XIV-A - Aperccedilu

Cliquez pour agrandir

XIV-B - Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mneacutemoniques ces derniers permettent dacceacuteder agrave un eacuteleacutementseacutequentiellement alors que les raccourcis appellent une fonction si lutilisateur appuie simultaneacutement sur une ouplusieurs touches (geacuteneacuteralement de la forme ltModificateurgtTouche ougrave Modificateur repreacutesente les touches ShiftAlt et Control) Ce raccourci peut ecirctre attacheacute agrave un eacuteleacutement du menu mais ceci nest pas obligatoire

Les raccourcis sont regroupeacutes en groupe dans un GtkAccelGroup quil faut commencer par creacuteer

raccourciscinclude ltgtkgtkhgtinclude callbackhinclude raccourcish

GtkAccelGroup accel_group_new (gpointer user_data) GtkAccelGroup p_accel_group = NULL

p_accel_group = gtk_accel_group_new () return p_accel_group

Vous commencez agrave avoir lhabitude de cette organisation nous allons donc creacuteer une fonction qui va se chargerdajouter un raccourci au groupe

raccourciscstatic void accelerator_new (GtkAccelGroup p_accel_group const gchar accelerator const gchar accel_path GCallback callback gpointer user_data) guint key GdkModifierType mods GClosure closure = NULL

gtk_accelerator_parse (accelerator ampkey ampmods) closure = g_cclosure_new (callback user_data NULL) gtk_accel_group_connect (p_accel_group key mods GTK_ACCEL_VISIBLE closure) gtk_accel_map_add_entry (accel_path key mods)

La fonction gtk_accelerator_parse permet de deacutecomposer une chaicircne de caractegraveres de la forme ltControlgtF1 ouencore ltAltgtA en numeacutero de touche et modificateur

En plus des touches pour creacuteer un raccourci clavier nous avons besoin dune fonction agrave appeler lorsque lutilisateurappuie sur les touches speacutecifieacutees gtk_accel_group_connect attend une fonction du type GClosure regardons ladocumentation de gobject pour savoir agrave quoi cela correspond

typedef struct

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 9 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Ceux qui se sont essayeacutes agrave la creacuteation dapplications graphiques avec lAPI Windows comprendront la simpliciteacutede ce code

II-D - Destruction

Dans lexemple preacuteceacutedent si vous avez essayeacute de terminer lapplication en fermant la fenecirctre (Alt+F4 ou en cliquantsur la petite croix) vous vous ecirctes peut-ecirctre aperccedilu que lapplication tournait encore en fond cest le mecircme problegravemeque pour le chapitre preacuteceacutedent on ne fait pas appel agrave gtk_main_quit Mais comment appeler cette fonction puisquequune fois gtk_main appeleacutee nous ne pouvons rien faire Cest lagrave quintervient le meacutecanisme des callback A chaqueeacuteveacutenement qui se produit la bibliothegraveque GObject produit un signal si nous souhaitons modifier le comportementpar deacutefaut du signal il suffit de connecter notre fonction callback agrave leacuteveacutenement souhaiteacute

define g_signal_connect(instance detailed_signal c_handler data)

Cette macro permet dintercepter leacuteveacutenement detailed_signal de lobjet instance gracircce agrave la fonction c_handler quidoit ecirctre du type GCallback

void (GCallback) (void)

Les fonctions callback peuvent bien sucircr recevoir des paramegravetres mais leur nature et leur nombre deacutependent ducontexte tout est geacutereacute par la bibliothegraveque GObject Le prototype le plus courant pour une fonction de rappel estle suivant

void callback (GtkWidget p_widget gpointer user_data)

Dont le premier paramegravetre est le widget qui a reccedilu le signal et le second correspond au paramegravetre data de la fonctiong_signal_connect qui nous permet de passer des informations aux fonctions callback Pour finir proprement notreapplication il suffit dintercepter le signal destroy de notre fenecirctre et dy assigner la fonction gtk_main_quit qui neprend pas dargument Voici donc notre premiegravere application fonctionnelle

maincinclude ltstdlibhgtinclude ltgtkgtkhgt

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (gtk_main_quit) NULL)

Affichage de la fenetre principale gtk_widget_show (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

Il est plus courant de creacuteer notre propre fonction de rappel pour quitter le programme ceci permet de libeacuterer lameacutemoire alloueacutee fermer les fichiers ouverts

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 10 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

maincinclude ltstdlibhgtinclude ltgtkgtkhgt

void cb_quit (GtkWidget gpointer)

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (cb_quit) NULL)

Affichage de la fenetre principale gtk_widget_show (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

void cb_quit (GtkWidget p_widget gpointer user_data) gtk_main_quit()

Parametres inutilises (void)p_widget (void)user_data

Le preacutefixe cb_ permet de diffeacuterencier les fonctions callback quil est preacutefeacuterable de regrouper dans un ou plusieursfichiers seacutepareacutes

A la fin de la fonction je transtype les paramegravetres inutiliseacutes pour eacuteviter que moncompilateur mindique des variables non utiliseacutees cest le problegraveme avec les fonctionscallback lAPI nous impose un prototype

II-E - Code source

chapitre2zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 11 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

III - Fermer notre fenecirctre gracircce aux boutons

III-A - Aperccedilu

III-B - Les boutons poussoir

Maintenant que notre programme se termine proprement il est plus convivial de proposer agrave lutilisateur un boutonpour quitter Pour creacuteer un bouton poussoir il existe plusieurs possibiliteacutes

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 premiegravere fonction creacutee un bouton qui peut servir pour contenir nimporte quel autre widget (label image) Si voussouhaitez creacuteer un bouton avec du texte dessus utilisez directement la seconde fonction qui prend en argument letexte agrave afficher Si vous souhaitez ajouter un raccourci clavier (accessible avec la touche Alt) la troisiegraveme fonctionpermet den speacutecifier un en faisant preacuteceacuteder une lettre (geacuteneacuteralement la premiegravere) dun underscore _ (si voussouhaitez afficher le caractegravere _ il faut en mettre deux) Enfin la derniegravere fonction permet dutiliser les Stock Itemsqui sont un ensemble deacuteleacutements preacutedeacutefinis par GTK+ pour les menus et barres doutils Le seul paramegravetre de cettefonction est le nom de leacuteleacutement et GTK+ se charge dafficher licocircne approprieacutee ainsi que le texte suivant la languechoisie et un raccourci

Cest bien sucircr cette derniegravere fonction que nous allons utiliser et ce le plus souvent possible Voici le code pour creacuteerun tel bouton

maincGtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_QUIT)

Pour obtenir tous les types de stocks items disponibles GtkStockItem

Bien sucircr comme pour la fenecirctre si lon veut voir quelque chose il faut demander agrave GTK+ dafficher notre widget

maincgtk_widget_show (p_button)

Mais pas seulement En effet il faut preacuteciser agrave GTK+ ougrave doit ecirctre afficheacute notre bouton Pour cela la classe GtkWindowest deacuteriveacutee de la classe GtkContainer qui est comme son nom le laisse penser un conteneur pour widget Pourajouter un widget il suffit de faire appel agrave la fonction gtk_container_add

void gtk_container_add (GtkContainer container GtkWidget widget)

Le premier paramegravetre de cette fonction est un GtkContainer or nous souhaitons passer notre fenecirctre qui est unGtkWidget pour ne pas avoir de problegravemes il faut utiliser le systegraveme de macro offert par GTK+ pour transtyper notreGtkWidget en GtkContainer (eh oui en C le polymorphisme a ses limites)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 12 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

maincgtk_container_add (GTK_CONTAINER (p_window) p_button)

Ce meacutecanisme de transtypage permet agrave GTK+ de veacuterifier que notre GtkWidget est bien compatible avec lutilisationque lon souhaite en faire En cas deacutechec GTK+ nous preacutevient en affichant un message dans la console

(gtk_boutonexe1044) Gtk-CRITICAL gtk_container_add assertion `GTK_IS_CONTAINER (container) failed

Pour finir il faut connecter notre bouton pour appeler notre fonction cb_quit lorsque lutilisateur clic dessus (ce quicorrespond agrave leacuteveacutenement clicked)

g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_quit) NULL)

Pour eacuteviter dappeler la fonction gtk_widget_show pour tous les widgets de notreapplication on peut se contenter dun seul appel agrave la fonction gtk_widget_show_all quipermet dafficher tous les widgets contenus dans celui passeacute agrave la fonction

maincinclude ltstdlibhgtinclude ltgtkgtkhgtinclude callbackh

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (cb_quit) NULL)

GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_QUIT) gtk_container_add (GTK_CONTAINER (p_window) p_button) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_quit) NULL)

Affichage de la fenetre principale gtk_widget_show_all (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

III-C - Code source

chapitre3zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 13 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IV - Comment afficher plusieurs widgets

IV-A - Aperccedilu

IV-B - Le problegraveme

Dans la partie preacuteceacutedente nous avons reacuteussi agrave afficher un bouton dans la fenecirctre de notre application Si vous avezessayeacute dajouter un second widget GTK+ agrave ducirc vous reacutepondre poliment

(gtk_boxexe492) Gtk-WARNING Attempting to add a widget with typeGtkButton to a GtkWindow but as a GtkBin subclass a GtkWindow can only containone widget at a time it already contains a widget of type GtkButton

Les plus anglophiles dentre vous auront compris que GTK+ naccepte pas lajout un second widget dans notre fenecirctretout simplement parce quil y en a deacutejagrave un et que la sous classe GtkBin (classe megravere de notre GtkWindow) ne peutcontenir quun seul widget

IV-C - La solutions

Pour contourner ce problegraveme il faut commencer par creacuteer un widget qui accepte den contenir plusieurs autrespour ensuite y ajouter tout ce dont nous avons besoin Pour linstant nous utiliserons quun seul widget (il existetrois classes qui permettent ceci) il sagit des GtkBox Il sagit de la meacutethode que jutilise le plus souvent Ce nestpeut-ecirctre pas la plus simple agrave maicirctriser mais elle extrecircmement souple et puissante Elle consiste agrave creacuteer une boicirctepuis agrave y ajouter les widgets les uns apregraves les autres (soit au deacutebut soit agrave la fin) Il existe deux classes heacuteritant deGtkBox les GtkVBox qui empilent les widgets dans le sens vertical et les GtkHBox qui font de mecircme mais dansle sens horizontal Les fonctions pour manipuler ces deux classes sont les mecircmes seule la fonction pour les creacuteerportent un nom diffeacuterent

GtkWidget gtk_vbox_new (gboolean homogeneous gint spacing)GtkWidget gtk_hbox_new (gboolean homogeneous gint spacing)

Le paramegravetre homogeneous permet de reacuteserver pour chaque widget une zone de taille identique (zone que le widgetnest pas obligeacute de remplir) et spacing permet dajouter une bordure en pixels (espacement autour de la GtkBox)Ensuite il suffit dajouter les diffeacuterents widgets gracircce aux fonctions

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)

Qui ajoutent reacuteciproquement le widget child au deacutebut et agrave la fin de box Le paramegravetre expand permet au widget davoirle plus de place possible (si le paramegravetre homogeneous vaut TRUE cette option a aucun effet) Si plusieurs widgetont ce paramegravetre agrave TRUE ils se partagent de faccedilon eacutegale lespace Loption fill permet au widget de remplir toutlespace qui lui ait reacuteserveacute

Pour reacuteellement comprendre linfluence de ces paramegravetres il faut faire des tests en modifiant un agrave un chaqueparamegravetre et observer les effets dun redimentionnement de la fenecirctre principale

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 14 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Le plus gecircnant avec cette meacutethode cest quil faut jongler entre les GtkHBox et les GtkVBox en les imbriquant pourobtenir le reacutesultat souhaiter nheacutesitez pas agrave utiliser une feuille et un crayon )

Pour en revenir agrave notre eacutediteur de texte nous allons preacuteparer notre application agrave contenir les futurs widgetsNous utilisons un GtkVBox pour lensemble des widgets (il sagit de la boicircte principale qui pourra contenir dautresGtkContainer selon nos besoins)

maincinclude ltstdlibhgtinclude ltgtkgtkhgtinclude callbackh

int main (int argc char argv) GtkWidget p_window = NULL GtkWidget p_main_box = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (cb_quit) NULL)

Creation du conteneur principal p_main_box = gtk_vbox_new (FALSE 0) gtk_container_add (GTK_CONTAINER (p_window) p_main_box)

Creation du bouton Quitter GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_QUIT) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_quit) NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_button FALSE FALSE 0)

Affichage de la fenetre principale gtk_widget_show_all (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

IV-D - Code source

chapitre4zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 15 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

V - Afficher le contenue dun fichier

V-A - Aperccedilu

Cliquez pour agrandir

V-B - Saisir du texte

Les choses seacuterieuses vont commencer il sagit de mettre en place le widget qui va nous permettre dafficher etdeacutediter du texte Il sagit de la classe GtkTextView Gracircce agrave GTK+ la mise en place est toujours aussi simple

mainc GtkWidget p_text_view = NULL Creation de la zone de texte p_text_view = gtk_text_view_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_text_view TRUE TRUE 0)

Comme il sagit de la partie centrale de notre application nous demandons agrave ce quelle prenne le plus de placepossible (gracircce agrave la fonction gtk_box_pack_start)

Puisque nous voulons afficher les boutons en dessous de la zone de texte il faut ajouter ce morceau de code avantcelui creacuteant le bouton

V-C - Ouvrir un fichier

Maintenant nous avons une belle zone de texte il faut la remplir avec le contenu dun fichier Pour ce faire nousallons commencer par ajouter un bouton ouvrir

mainc Creation du bouton Ouvrir GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_OPEN) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_open) p_text_view) gtk_box_pack_start (GTK_BOX (p_main_box) p_button FALSE FALSE 0)

Si vous exeacutecutez le programme maintenant (3) vous remarquerez que les boutons sont ajouteacutes les uns en dessousdes autres ce qui diminue la zone de saisie (avec deux boutons ce nest pas gecircnant mais au bout dune dizaineccedila risque decirctre probleacutematique) Pour pallier ce problegraveme nous allons utiliser un nouveau style de GtkBox lesGtkButtonBox qui sont preacutevus pour contenir des boutons (ccedila tombe plutocirct bien D) Donc pour eacuteviter de diminuerla zone de saisie et comme nous avons de la place en largueur nous allons utiliser un GtkHButtonBox qui va ecirctreinclus dans la p_main_box Voici les modifications agrave effectuer

mainc GtkWidget p_button_box = NULL Creation du conteneur pour les boutons p_button_box = gtk_hbutton_box_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_button_box FALSE FALSE 0)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 16 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc gtk_box_pack_start (GTK_BOX (p_button_box) p_button FALSE FALSE 0) gtk_box_pack_start (GTK_BOX (p_button_box) p_button FALSE FALSE 0)

Maintenant il nous reste plus quagrave creacuteer la fonction cb_open dans le fichier callbackc pour linstant nous nouscontenterons douvrir toujours le mecircme fichier nous verrons plus tard comment laisser le choix agrave lutilisateur

callbackcdefine DEFAULT_FILE mainc

void cb_open (GtkWidget p_widget gpointer user_data) open_file (DEFAULT_FILE GTK_TEXT_VIEW (user_data))

Parametre inutilise (void)p_widget

Vous aurez compris que lon va deacuteleacuteguer tout le travail agrave la fonction open_file qui devra ouvrir le fichier dont le nomest passeacute en premier paramegravetre pour lafficher dans le GktTextView

Jai fait ce choix pour deux raisons le code dune fonction callback peut ecirctre tregraves conseacutequent (surtout si lon souhaitequelle affiche une boicircte de dialogue) et aussi parce que cb_open nest peut ecirctre pas la seule fonction agrave copierun fichier dans un GtkTextView (par exemple lors de la creacuteation dun nouveau fichier lon peut vouloir copier unsquelette de fichier)

Pour copier notre fichier plutocirct que dutiliser la fonction fgets nous allons nous servir de la glib (4) qui proposela fonction

gboolean g_file_get_contents (const gchar filename gchar contents gsize length GError error)

Qui nous renvoit le contenu du fichier nommeacute filename dans le tampon contents Il est possible de reacutecupeacuterer lenombre de caractegraveres copieacutes et retourne TRUE en cas de succegraves sinon FALSE et dans ce cas une structure de typeGError est creacutee pour en savoir plus sur le type derreur rencontreacute

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView else print_warning (Impossible douvrir le fichier sn file_name)

Je pense quun certain nombre dexplications simpose (surtout si je vais trop vite nheacutesitez pas agrave marrecircter )

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 17 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

bull g_return_if_fail est une macro qui peut ecirctre compareacutee agrave assert sauf quelle se contente de sortir de la fonctionsi lexpression passeacutee en paramegravetre est fausse Cest une meacutethode pratique pour veacuterifier la validiteacute desparamegravetres (si la fonction doit retourne une valeur utiliseacute plutocirct g_return_val_if_fail qui prend un secondparamegravetre la valeur agrave retourner)

bull Ensuite on essaie de reacutecupeacuterer le contenu de notre fichier

bull Si cela eacutechoue nous le signalons agrave lutilisateur agrave laide de la fonction print_warning

bull Le type gchar est une redeacutefinition du type char par la glib (il en va de mecircme pour tous les autres types du C)privileacutegiez ces types lorsque vous utilisez des fonctions de cette bibliothegraveques

Mais quest-ce donc cette fonction print_warning Cest une fonction que nous allons creacuteer semblable agrave printf quisignalera agrave lutilisateur quune erreur non critique est survenue Comme nous navons pas encore abordeacute les boicirctesde dialogue pour afficher un message il sagira pour linstant dune simple redeacutefinition de printf Pendant que noussommes dans laffichage des messages nous allons aussi creacuteer deux fonctions print_info et print_error qui vontrespectivement afficher un message dinformation et un message derreur critique (ce qui entraicircne la terminaison duprogramme) tout ceci dans un nouveau fichier errorc

errorhifndef H_ERRORdefine H_ERROR

void print_info (char )void print_warning (char )void print_error (char )

endif not H_ERROR

errorcinclude ltstdarghgtinclude ltstdiohgtinclude ltstdlibhgtinclude errorh

void print_info (char format ) va_list va

va_start (va format) printf (Information ) vprintf (format va) printf (n)

void print_warning (char format ) va_list va

va_start (va format) fprintf (stderr Erreur ) vfprintf (stderr format va) fprintf (stderr n)

void print_error (char format ) va_list va

va_start (va format) fprintf (stderr Erreur fatale ) vfprintf (stderr format va) fprintf (stderr n) exit (EXIT_FAILURE)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 18 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

Pour en finir avec louverture dun fichier il nous reste agrave copier contents dans le GtkTextView En fait le GtkTextViewne gegravere que la forme pour modifier le contenu il faut passer par les GtkTextBuffer Commenccedilons donc par reacutecupeacutererce fameux GtkTextBuffer

callbackc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (p_text_view)

Et pour finir on utilise la fonction

void gtk_text_buffer_insert (GtkTextBuffer buffer GtkTextIter iter const gchar text gint len)

Reacutecapitulons buffer est le GtkTextBuffer que lon vient de reacutecupeacuterer text cest le texte agrave afficher et len la taille dece dernier (ou -1 sil sagit dune chaicircne de caractegraveres au sens du langage C)

Mais quest-ce donc ce GtkTextIter On peut voir cela comme un curseur virtuel qui indique la position agrave laquelleeffectuer linsertion de texte dans le GtkTextBuffer (5) Allons voir ce que la documentation peut nous apprendreagrave leur sujet (6)

typedef struct GtkTextIter is an opaque datatype ignore all these fields Initialize the iter with gtk_text_buffer_get_iter_ functions GtkTextIter

Voilagrave on a notre solution suffit de rechercher les fonctions commenccedilant par gtk_text_buffer_get_iter_ voici la liste

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)

La fonction gtk_text_buffer_get_iter_at_line fait parfaitement laffaire

callbackc GtkTextIter iter

gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1)

Cependant si vous ne voulez pas avoir de problegravemes avec le codage des caractegraveres il vaut mieux convertir le codagelocal vers utf8 Voici le reacutesultat final

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 19 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gchar utf8 = NULL GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_text_buffer_insert (p_text_buffer ampiter utf8 -1) g_free (utf8) utf8 = NULL

V-D - La petite touche finale

Pour finir cette laborieuse partie sur une petite touche estheacutetique nous allons demander agrave GTK+ de nous lancerlapplication en plein eacutecran Pour se faire il suffit dajouter lors de la creacuteation de la fenecirctre principale

maincgtk_window_maximize (GTK_WINDOW (p_window))

On peut mecircme se permettre une pointe dexcentriciteacute en modifiant le titre de notre fenecirctre

maincgtk_window_set_title (GTK_WINDOW (p_window) Editeur de texte en GTK+)

V-E - Code source

chapitre5zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 20 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VI - Choisir un fichier

VI-A - Aperccedilu

Cliquez pour agrandir

VI-B - Utilisation dun GtkFileChooserFile

Jusquagrave preacutesent lutilisateur navait pas le choix quant au fichier agrave ouvrir heureusement GTK+ vient agrave notre aide gracircceau widget GtkFileChooserFile qui est tout simplement une boicircte de dialogue qui propose agrave lutilisateur de seacutelectionnerun fichier dans son arborescence disque

Commenccedilons par creacuteer notre boicircte de dialogue dans la fonction cb_open

callbackcvoid cb_open (GtkWidget p_widget gpointer user_data) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Ouvrir un fichier NULL GTK_FILE_CHOOSER_ACTION_OPEN GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_OPEN GTK_RESPONSE_ACCEPT NULL)

Cette fonction neacutecessite le titre de la boicircte de dialogue une fenecirctre parente le type daction (ici on souhaite ouvrir unfichier GTK+ autorisera lutilisateur agrave seacutelectionner uniquement les fichiers existants) Pour finir il sagit dun couple devaleurs GTK_STOCK_ITEMGTK_STOCK_RESPONSE qui permet de creacuteer un bouton utilisant le stock ID speacutecifieacuteet lorsque celui-ci est cliqueacute la fonction servant agrave lancer la boicircte de dialogue retournera le reacuteponse ID correspondantIl existe une seacuterie de valeurs deacutefinies par GTK+ quil est conseilleacute dutiliser

typedef enum GTK returns this if a response widget has no response_id or if the dialog gets programmatically hidden or destroyed GTK_RESPONSE_NONE = -1

GTK wont return these unless you pass them in as the response for an action widget They are for your convenience GTK_RESPONSE_REJECT = -2 GTK_RESPONSE_ACCEPT = -3

If the dialog is deleted GTK_RESPONSE_DELETE_EVENT = -4

These are returned from GTK dialogs and you can also use them yourself if you like GTK_RESPONSE_OK = -5 GTK_RESPONSE_CANCEL = -6 GTK_RESPONSE_CLOSE = -7 GTK_RESPONSE_YES = -8

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 21 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GTK_RESPONSE_NO = -9 GTK_RESPONSE_APPLY = -10 GTK_RESPONSE_HELP = -11 GtkResponseType

Nous indiquons la fin des couples stock idreacuteponse id avec la valeur NULL

Une fois la boicircte de dialogue creacuteee on demande agrave GTK+ de lafficher gracircce agrave la fonction gtk_dialog_run puis onreacutecupegravere sa valeur de retour qui correspond au bouton cliqueacute par lutilisateur

callbackc if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

Ici ce qui nous inteacuteresse cest lorsque que lutilisateur clique sur le bouton ouvrir (donc gtk_dialog_run renvoieGTK_RESPONSE_ACCEPT) dans ce cas il nous suffit de reacutecupeacuterer le nom du fichier seacutelectionneacute puis de louvrir

callbackc gchar file_name = NULL

file_name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) open_file (file_name GTK_TEXT_VIEW (user_data)) g_free (file_name) file_name = NULL

Pour finir dans tous les cas on noublie pas de deacutetruire la boicircte de dialogue

callbackc gtk_widget_destroy (p_dialog)

Et voilagrave le travail lutilisateur peut ouvrir le fichier quil souhaite

VI-C - Code source

chapitre6zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 22 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VII - Interlude

Avant daller plus loin dans lameacutelioration de linterface de notre eacutediteur il est neacutecessaire de modifier sonfonctionnement interne (ne vous inquieacutetez je nai pas dit chambouler) en effet souvenez-vous dans lintroduction jaieacutevoqueacute la possibiliteacutes douvrir plusieurs documents gracircce agrave un systegraveme donglets Pour cela il faut sauvegarder lesproprieacuteteacutes de chaque document ouvert Pris agrave temps ce genre de modification nest pas trop lourde mais si nousattendons cela risque de devenir un vrai casse tecircte

Pour cela nous allons utiliser une structure de donneacutee pour chaque document ouvert qui devra garder en meacutemoirele chemin complet du fichier (ou NULL si le document nest pas encore sauvegarder) sil agrave eacutetait modifier depuis laderniegravere sauvegarde et le GtkTextView qui sert agrave son affichage Voici donc la structure qui va nous servir

documenthtypedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

Sachant que nous serons ameneacute agrave stocker plusieurs occurrences de cette structure il serait bon de reacutefleacutechir degravesmaintenant agrave la structure de donneacutee agrave utiliser pour les stocker La premiegravere ideacutee qui vient agrave lesprit est un tableaualloueacute dynamiquement cependant lutilisateur peut souhaiter fermer un document qui se trouve au milieu on estalors obligeacute de deacutecaler toutes les cellules en amont Dans ce cas il parait naturel dutiliser une liste chaicircneacutee Parchance la glib propose une bibliothegraveque de gestion des listes chaicircneacutees cela nous fera gagner du temps le momentvenu Pour linstant on se contente de creacuteer une structure de donneacutees qui contiendra tous les documents ouverts(stockeacutee dans une GList) et un pointeur sur le document actif (actuellement comme nous navons quun documentouvert en mecircme temps on manipulera uniquement ce pointeur)

documenthtypedef struct GList tous document_t actif docs_t

Maintenant se pose le problegraveme de savoir comment transmettre cette structure On pourrait se servir du paramegravetreuser_data preacutesent dans toutes les fonctions callback mais certaines fonctions utilise deacutejagrave ce paramegravetre (la fonctioncb_open par exemple) il faudrait creacuteer un champs suppleacutementaire dans notre structure documents_s Une solutionplus simple est de creacuteer une variable globale agrave lensemble du programme Ceux qui passe reacuteguliegraverement sur le forumC savent que cest fortement deacuteconseilleacute mais ici nous nous trouvons dans lune des rares exceptions agrave la regravegle Detoute faccedilon cela revient au mecircme que de passer ladresse de notre structure agrave toutes les fonctions callback Nousdeacutefinissons donc un nouveau fichier den-tecircte

documenthifndef H_DOCUMENTdefine H_DOCUMENT

include ltgtkgtkhgt

typedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 23 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

documenthtypedef struct GList tous document_t actif docs_t

extern docs_t docs

endif not H_DOCUMENT

Et dans le fichier mainc

maincinclude documenth

docs_t docs = NULL NULL

Pour linstant la seule fonction qui modifie leacutetat dun document est la fonction open_file il faut donc inclure documenthdans callbackc et modifier leacutegegraverement la fonction pour enregistrer le document ouvert

callbackc if (g_file_get_contents (file_name ampcontents NULL NULL)) Pour linstant il faut allouer la memoire par la suite on modifira simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = g_strdup (file_name) Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = p_text_view Le document vient detre ouvert il nest donc pas modifie docsactif-gtsauve = TRUE

Ne soyez pas choqueacute si je ne teste pas le retour de la fonction g_malloc pour veacuterifier quilnest pas NULL En effet cette derniegravere met fin agrave lapplication si lallocation eacutechoue

VII-A - Code source

chapitre7zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 24 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VIII - Sauvegarder les modification

VIII-A - Aperccedilu

Cliquez pour agrandir

VIII-B - Enregistrer

Avant de pouvoir sauvegarder un document il faut quil soit modifieacute Comment savoir que le contenu du fichier a eacuteteacutemodifier Gracircce au signal changed du GtkTextBuffer que nous interceptons gracircce agrave la fonction cb_modifie

mainc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (p_text_view)) g_signal_connect (G_OBJECT (p_text_buffer) changed G_CALLBACK (cb_modifie) NULL)

Cette derniegravere modifie simplement le champ sauve du document

callbackcvoid cb_modifie (GtkWidget p_widget gpointer user_data) if (docsactif) docsactif-gtsauve = FALSE

Pour la sauvegarde il faut distinguer deux cas soit il sagit de la premiegravere sauvegarde du fichier il faut alors demanderle nom du fichier agrave lutilisateur (cela ressemble fortement agrave louverture dun fichier) soit le fichier est deacutejagrave preacutesent surle disque il suffit de remplacer son contenu par celui du GtkTextViewer Nous avons convenu quun fichier qui neacutetaitpas encore enregistreacute avait sa proprieacuteteacute chemin agrave NULL

Bien sucircr cela na lieu que si un fichier est ouvert et quil a eacuteteacute modifieacute depuis sa derniegravere sauvegarde

callbackcvoid cb_save (GtkWidget p_widget gpointer user_data) if (docsactif) if (docsactif-gtsauve) Le fichier na pas encore ete enregistre if (docsactif-gtchemin) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Sauvegarder le fichier NULL GTK_FILE_CHOOSER_ACTION_SAVE GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_SAVE GTK_RESPONSE_ACCEPT NULL) if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 25 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc docsactif-gtchemin = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) gtk_widget_destroy (p_dialog) Soit le fichier a deja ete enregistre soit lutilisateur vient de nous fournir son nouvel enplacement on peut donc lenregistrer if (docsactif-gtchemin) else print_warning (Aucun document ouvert)

Il nous reste plus quagrave reacutecupeacuterer le contenu du GtkTextViewer et le copier dans le fichier chemin sans oublier dereconvertir le texte dans le codage local

callbackc FILE fichier = NULL

fichier = fopen (docsactif-gtchemin w) if (fichier) gchar contents = NULL gchar locale = NULL GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) contents = gtk_text_buffer_get_text (p_text_buffer ampstart ampend FALSE) locale = g_locale_from_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL fprintf (fichier s locale) g_free (locale) locale = NULL fclose (fichier) fichier = NULL docsactif-gtsauve = TRUE else print_warning (Impossible de sauvegarder le fichier s docsactif-gtchemin)

Le dernier paramegravetre de la fonction gtk_text_buffer_get_text est mis agrave FALSE car nous ne voulons pas enregistrerles caractegraveres invisibles preacutesent dans le GtkTextBuffer Ces caractegraveres servent agrave mettre en forme le texte (taillecouleur) nous pourrions creacuteer un nouveau format de fichier pour enregistrer la mise en forme

VIII-C - Enregistrer sous

Pour enregistrer notre document sous un autre nom il suffit de faire croire agrave cb_save que le document na pas encoreeacutetait enregistreacute tout simplement en changeant chemin agrave NULL et sauve agrave FALSE

callbackcvoid cb_saveas (GtkWidget p_widget gpointer user_data)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 26 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (docsactif) document_t tmp = docsactif

docsactif-gtchemin = NULL docsactif-gtsauve = FALSE cb_save (p_widget user_data) if (docsactif-gtsauve) (docsactif) = tmp else print_warning (Aucun document ouvert)

Il ne faut pas oublier que lutilisateur peut annuler lenregistrement de ce fait nous sauvegardons leacutetat du documentet si la sauvegarde na pas eu lieu on le restaure

VIII-D - Code source

chapitre8zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 27 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IX - Creacuteer un nouveau document

IX-A - Aperccedilu

Cliquez pour agrandir

IX-B - Nouveau fichier

Maintenant que lutilisateur peut ouvrir et fermer un fichier il est inteacuteressant de lui donner la possibiliteacute den creacuteerun nouveau Je ne reviens pas sur la creacuteation du bouton (ccedila devrait deacutejagrave ecirctre fait D) passons directement agrave lafonction cb_new

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) Pour linstant il faut allouer la memoire par la suite on modifiera simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = NULL Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = GTK_TEXT_VIEW (user_data) Le document vient detre creer il nest donc pas modifie docsactif-gtsauve = TRUE gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Je ne sais pas vous mais pour ma part jai fait un copiercoller de la fonction open_file Et oui ouvrir un document peutse reacutesumer agrave creacuteer un document vide puis remplir le GtkTextView avec le fichier souhaiteacute On peut donc simplifiernotre fonction open_file ainsi

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

cb_new (NULL p_text_view) gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE) p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1) Nous sommes obliges de remetre sauve a TRUE car linsertion du contenu du fichier dans le GtkTextView a appele cb_modfie docsactif-gtsauve = TRUE else print_warning (Impossible douvrir le fichier sn file_name)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 28 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc

Cest beau la factorisation du code Par contre nous sommes obligeacutes de remettre sauve agrave TRUE car nous avonsmodifieacute le GtkTextBuffer

IX-C - Code source

chapitre9zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 29 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

X - Fermer

X-A - Aperccedilu

Cliquez pour agrandir

X-B - Fermer un fichier

Maintenant que nous allouons de la meacutemoire il faut la libeacuterer agrave un endroit Logiquement cela va ecirctre fait agrave la fermeturedu document en guise dexercice je vous laisse creacuteer le bouton dans notre boicircte agrave bouton

Allez je vous aide le stock id correspondant est GTK_STOCK_CLOSE

Voilagrave maintenant si tout cest bien passeacute vous devriez ecirctre arriveacute dans le fichier callbackc avec quelque choseressemblant agrave

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data)

Lorsque lon ferme un document il faut vider le GtkTextView (avec les onglets on se contentera de le supprimer)pour cela il faut reacutecupeacuterer le deacutebut et la fin du GtkTextBuffer et demander agrave GTK+ de supprimer tout ce qui ce trouveentre les deux iteacuterateurs

callbackc Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) gtk_text_buffer_delete (p_text_buffer ampstart ampend) else print_warning (Aucun document ouvert)

Bien sucircr il ne faut pas oublier de libeacuterer la meacutemoire

callbackc g_free (docsactif-gtchemin) docsactif-gtchemin = NULL docsactif-gtp_text_view = NULL g_free (docsactif) docsactif = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 30 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour symboliser la fermeture dun document nous deacutesactivons le GtkTextView lors de la fermeture (ne pas oublierde le faire aussi dans mainc)

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) FALSE)

Et nous le reacuteactivons lors de louverture si celle si reacuteussie

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Lorsque lutilisateur quitte lapplication il faut bien sucircr fermer le document sil y en a un ouvert

void cb_quit (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data) gtk_main_quit()

Et aussi lorsquil creacuteeacute un nouveau document (et par conseacutequent lorsquil ouvre un fichier puisque lon fait appel agravecb_new)

void cb_new (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data)

X-C - Enregistrer avant de fermer

Si le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde geacuteneacuteralement le programme le signale agrave lutilisateur etlui propose de sauvegarder ou dannuler la fermeture Pour se faire nous devons modifier la fonction cb_close avantde fermer le document nous allons afficher une boicircte de dialogue

Pour creacuteer une boicircte de dialogue simplement il existe la classe GtkDialog et comme nous avons besoin de boutons(pour que lutilisateur fasse son choix) nous allons creacuteer notre boicircte avec la fonction

GtkWidget gtk_dialog_new_with_buttons (const gchar title GtkWindow parent GtkDialogFlags flags const gchar first_button_text )

Nous retrouvons les mecircmes options que pour le GtkFileChooserDialog mis agrave part option du type GtkDialogFlags

typedef enum GTK_DIALOG_MODAL = 1 ltlt 0 appel gtk_window_set_modal (win TRUE) GTK_DIALOG_DESTROY_WITH_PARENT = 1 ltlt 1 appel gtk_window_set_destroy_with_parent () GTK_DIALOG_NO_SEPARATOR = 1 ltlt 2 Pas de barre de separation au dessus des boutons GtkDialogFlags

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 31 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Nous nous contenterons de rendre notre fenecirctre modale (7)

Pour avoir accegraves agrave notre fenecirctre principale nous ajoutons un champs p_main_window agrave notre structure globaledocs_t que nous initialisons dans la fonction main

mainc docsp_main_window = GTK_WINDOW (p_window)

Il nous reste plus qua creacuteer notre boicircte de dialogue avec trois boutons Oui Non Annuler

callbackc if (docsactif-gtsauve) GtkWidget p_dialog = NULL

p_dialog = gtk_dialog_new_with_buttons (Sauvegarder docsp_main_window GTK_DIALOG_MODAL GTK_STOCK_YES GTK_RESPONSE_YES GTK_STOCK_NO GTK_RESPONSE_NO GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL NULL)

Nous obtenons donc une structure de type GtkDialog

typedef struct GtkWidget vbox GtkWidget action_area GtkDialog

Nous remarquons que cette structure contient deux membres qui permettent dacceacuteder agrave une GtkBox ougrave nous allonsajouter le contenu de la fenecirctre et agrave la partie contenant les boutons

Ensuite la construction de la fenecirctre est identique agrave celle de la fenecirctre principale ici nous nous contenterons dajouterun GtkLabel

callbackc GtkWidget p_label = NULL p_label = gtk_label_new (Voulez-vous sauvegarder les modifications ) gtk_box_pack_start (GTK_BOX (GTK_DIALOG (p_dialog)-gtvbox) p_label TRUE TRUE 0)

Une fois notre fenecirctre precircte il suffit de faire appel agrave la fonction gtk_dialog_run qui va afficher notre GtkDialog et nousretourner le reacuteponse id correspondant au bouton cliqueacute par lutilisateur

callbackc switch (gtk_dialog_run (GTK_DIALOG (p_dialog))) case GTK_RESPONSE_YES cb_save (p_widget user_data) break case GTK_RESPONSE_NO break case GTK_RESPONSE_CANCEL gtk_widget_destroy (p_dialog) return break

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 32 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc gtk_widget_destroy (p_dialog)

Si lutilisateur clique sur non on ne fait rien (le document sera simplement fermeacute) sur oui on enregistre avant defermer et pour finir sil annule on quitte la fonction

X-D - Code source

chapitre10zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 33 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XI - Les barres de deacutefilement

XI-A - Aperccedilu

Cliquez pour agrandir

XI-B - Ajouter des barres de deacutefilement

Apregraves le dernier chapitre quelque peu laborieux voici une partie plus simple mais qui va rendre notre applicationplus pratique En effet si vous avez essayeacute douvrir un fichier de grande taille vous avez pu remarquer que pourpouvoir lire la fin du fichier il fallait utiliser les touches du clavier pas tregraves convivial

Pour rendre la navigation plus aiseacutee on utilise des barres de deacutefilement

mainc GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_scrolled_window TRUE TRUE 0)

Creation de la zone de texte gtk_container_add (GTK_CONTAINER (p_scrolled_window) p_text_view)

Le constructeur de notre GtkScrolledWindow prend en argument deux GtkAdjustment qui permettent de deacutefinirdiffeacuterentes proprieacuteteacutes de la barre de deacutefilement (taille dune page la position de deacutepart) nous laissons GTK+ faireen passant NULL

Cest un bon deacutebut mais estheacutetiquement on peut faire mieux mecircme sil nest pas utile davoir une barre de deacutefilementelle est quand mecircme afficheacutee On peut demander agrave GTK+ de les afficher que si cela est neacutecessaire

mainc gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC)

En fait nous avons de la chance car la classe GtkTextView fait partie des widget qui supporte de faccedilon native les barresde deacutefilement Comment le savoir Ce genre de widget possegravede une ou deux proprieacuteteacutes de type GtkAdjustment (unepour la barre verticale lautre pour la barre horizontale) Actuellement seulement trois classes en sont capables lesGtkTextView les GtkTreeView et les GtkLayout

Comment faire pour les autres widgets Il faut passer par une classe adaptateur GtkViewport afin de creacuteer lesGtkAdjustment

XI-C - Code source

chapitre11zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 34 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XII - Les menus

XII-A - Aperccedilu

Cliquez pour agrandir

XII-B - Creacuteation du menu

Pour simplifier nous avons utiliseacute des boutons pour permettre agrave lutilisateur de creacuteer un document ouvrir un fichierMais il est plus courant dutiliser un menu pour afficher ces options GTK+ propose trois maniegraveres de creacuteer un menu

bull GtkItemFactory cette meacutethode est obsolegravete depuis la version 24 de GTK+

bull GtkUIManager cest ce quon appel une usine agrave gaz pour en savoir plus vous pouvez vous reporter aututoriel Utilisation de GtkUIManager

bull GtkMenu cest ce widget que nous allons eacutetudier il permet de creacuteer un menu manuellement (agrave lopposeacute deGtkUIManager)

Un menu selon GTK+ est composeacute de plusieurs eacuteleacutements

bull GtkMenuBar la barre de menu elle-mecircme

bull GtkMenu la partie deacuteroulante qui contient les diffeacuterents eacuteleacutements

bull GtkMenuItem cest sur ce widget que lutilisateur clique pour lancer une action

Pour commencer faisons linventaire de ce que nous avons besoin

bull Un GtkMenuBar qui sert de base au menu

bull Un GtkMenu pour commencer nous nous aurons dun menu Fichier

bull Six GtkMenuItem pour remplacer nos six boutons

Commenccedilons par la creacuteation du menu nous mettons ce code dans un nouveau fichier dont seul la fonction menu_newsera accessible

menucGtkMenuBar menu_new (gpointer user_data) GtkWidget p_menu_bar = NULL

p_menu_bar = gtk_menu_bar_new () return GTK_MENU_BAR (p_menu_bar)

Le paramegravetre user_data nous servira lors de la connexion des callbacks (nous en avons besoin pour les fonctionscb_new et cb_open)

Ensuite nous allons creacuteer notre sous menu Fichier

menuc Menu Fichier

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 35 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

menuc GtkWidget p_menu = NULL GtkWidget p_menu_item = NULL

p_menu = gtk_menu_new () p_menu_item = gtk_menu_item_new_with_mnemonic (_Fichier) gtk_menu_item_set_submenu (GTK_MENU_ITEM (p_menu_item) p_menu) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu_bar) p_menu_item) return GTK_MENU_BAR (p_menu_bar)

Un sous menu est en fait un GtkMenuItem auquel on assigne un GtkMenu Il faut bien sucircr terminer la creacuteation dusous-menu en lajoutant agrave la barre de menu

Pour finir nous creacuteons les eacuteleacutements du menu les GtkItemMenu Il existe plusieurs types deacuteleacutements (comparableaux diffeacuterents types de bouton) pour commencer nous nutiliserons que le type de base Comme cette opeacuteration estreacutepeacutetitive nous allons creacuteer une fonction pour le faire

menucstatic void menu_item_new (GtkMenu p_menu const gchar title GCallback callback gpointer user_data) GtkWidget p_menu_item = NULL

p_menu_item = gtk_menu_item_new_with_mnemonic (title) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu) p_menu_item) g_signal_connect (G_OBJECT (p_menu_item) activate callback user_data)

Pour permettre agrave lutilisateur dacceacuteder aux diffeacuterents eacuteleacutements du menu agrave laide de la touche ltAltgt nous utilisonsdes mneacutemoniques par exemple pour quitter leacutediteur il suffit de faite Alt+F puis Q Et voici le code pour creacuteer nossix eacuteleacutements du menu

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau G_CALLBACK (cb_new) user_data) menu_item_new (GTK_MENU (p_menu) _Ouvrir G_CALLBACK (cb_open) user_data) menu_item_new (GTK_MENU (p_menu) _Enregistrer G_CALLBACK (cb_save) user_data) menu_item_new (GTK_MENU (p_menu) Enregistrer _sous G_CALLBACK (cb_saveas) user_data) menu_item_new (GTK_MENU (p_menu) _Fermer G_CALLBACK (cb_close) user_data) menu_item_new (GTK_MENU (p_menu) _Quitter G_CALLBACK (cb_quit) user_data)

Voilagrave notre menu est creacuteeacute il nous reste plus quagrave linteacutegrer agrave notre fenecirctre

mainc gtk_box_pack_start (GTK_BOX (p_main_box) GTK_WIDGET (menu_new (p_text_view)) FALSE FALSE 0)

Le problegraveme cest que nous avons besoin de passer le GtkTextView lors de la creacuteation du menu (qui est utiliseacute par lesfonctions cb_new et cb_open) or celui-ci est creacuteeacute apregraves le menu (puisque nous creacuteons les widgets dans lordre ougrave ilfaut les inteacutegrer agrave linterface (8) ) nous devons creacuteer le GtkTextView (seul lappel agrave gtk_text_view_new est deacuteplaceacute)

XII-C - Code source

chapitre12zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 36 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIII - Les barres doutils

XIII-A - Aperccedilu

Cliquez pour agrandir

XIII-B - Creacuteation dune barre doutils

La creacuteation dune barre doutils ressemble fort agrave celle dun menu en plus simple puisquil ny a pas de sous menu on creacutee notre barre doutils (gtk_toolbar_new) puis les eacuteleacutements de la barre pour cela on utilise des boutons(gtk_tool_button_new_from_stock) que lon inseacutere dans la barre (gtk_toolbar_insert) Pas conseacutequent notre fichierbarreoutilsc ressemble agrave menuc

barreoutilscinclude ltgtkgtkhgtinclude callbackhinclude barreoutilsh

static void toolbar_item_new (GtkToolbar const gchar GCallback gpointer)

GtkToolbar toolbar_new (gpointer user_data) GtkWidget p_toolbar = NULL

p_toolbar = gtk_toolbar_new () toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_NEW G_CALLBACK (cb_new) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_OPEN G_CALLBACK (cb_open) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE G_CALLBACK (cb_save) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE_AS G_CALLBACK (cb_saveas) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_CLOSE G_CALLBACK (cb_close) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_QUIT G_CALLBACK (cb_quit) user_data) return GTK_TOOLBAR (p_toolbar)

static void toolbar_item_new (GtkToolbar p_toolbar const gchar stock_id GCallback callback gpointer user_data) GtkToolItem p_tool_item = NULL

p_tool_item = gtk_tool_button_new_from_stock (stock_id) g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data) gtk_toolbar_insert (p_toolbar p_tool_item -1)

Le code nest pas complet car lorsque jexeacutecute le programme GTK+ affiche en plus des icocircnes le texte sous lesboutons Pour modifier cela il suffit dajouter une ligne de code

barreoutilsc gtk_toolbar_set_style (GTK_TOOLBAR (p_toolbar) GTK_TOOLBAR_ICONS)

Pourquoi gtk_tool_button_new_from_stock retourne un GtkToolItem et non un GtkWidgetcomme nous avons eacuteteacute habitueacute jusquagrave preacutesent Il sagit dune bizarrerie de GTK+ dontje ne connais pas la raison

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 37 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour anticiper un changement dinterface (dans GTK+ 30 peut ecirctre ) nous aurions pueacutecrire

Gtkwidget p_tool_item = NULL

p_tool_item = GTK_WIDGET (gtk_tool_button_new_from_stock (stock_id))g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data)gtk_toolbar_insert (p_toolbar GTK_TOOL_ITEM (p_tool_item) -1)

XIII-C - Code source

chapitre13zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 38 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIV - Les racourcis clavier

XIV-A - Aperccedilu

Cliquez pour agrandir

XIV-B - Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mneacutemoniques ces derniers permettent dacceacuteder agrave un eacuteleacutementseacutequentiellement alors que les raccourcis appellent une fonction si lutilisateur appuie simultaneacutement sur une ouplusieurs touches (geacuteneacuteralement de la forme ltModificateurgtTouche ougrave Modificateur repreacutesente les touches ShiftAlt et Control) Ce raccourci peut ecirctre attacheacute agrave un eacuteleacutement du menu mais ceci nest pas obligatoire

Les raccourcis sont regroupeacutes en groupe dans un GtkAccelGroup quil faut commencer par creacuteer

raccourciscinclude ltgtkgtkhgtinclude callbackhinclude raccourcish

GtkAccelGroup accel_group_new (gpointer user_data) GtkAccelGroup p_accel_group = NULL

p_accel_group = gtk_accel_group_new () return p_accel_group

Vous commencez agrave avoir lhabitude de cette organisation nous allons donc creacuteer une fonction qui va se chargerdajouter un raccourci au groupe

raccourciscstatic void accelerator_new (GtkAccelGroup p_accel_group const gchar accelerator const gchar accel_path GCallback callback gpointer user_data) guint key GdkModifierType mods GClosure closure = NULL

gtk_accelerator_parse (accelerator ampkey ampmods) closure = g_cclosure_new (callback user_data NULL) gtk_accel_group_connect (p_accel_group key mods GTK_ACCEL_VISIBLE closure) gtk_accel_map_add_entry (accel_path key mods)

La fonction gtk_accelerator_parse permet de deacutecomposer une chaicircne de caractegraveres de la forme ltControlgtF1 ouencore ltAltgtA en numeacutero de touche et modificateur

En plus des touches pour creacuteer un raccourci clavier nous avons besoin dune fonction agrave appeler lorsque lutilisateurappuie sur les touches speacutecifieacutees gtk_accel_group_connect attend une fonction du type GClosure regardons ladocumentation de gobject pour savoir agrave quoi cela correspond

typedef struct

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 10 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

maincinclude ltstdlibhgtinclude ltgtkgtkhgt

void cb_quit (GtkWidget gpointer)

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (cb_quit) NULL)

Affichage de la fenetre principale gtk_widget_show (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

void cb_quit (GtkWidget p_widget gpointer user_data) gtk_main_quit()

Parametres inutilises (void)p_widget (void)user_data

Le preacutefixe cb_ permet de diffeacuterencier les fonctions callback quil est preacutefeacuterable de regrouper dans un ou plusieursfichiers seacutepareacutes

A la fin de la fonction je transtype les paramegravetres inutiliseacutes pour eacuteviter que moncompilateur mindique des variables non utiliseacutees cest le problegraveme avec les fonctionscallback lAPI nous impose un prototype

II-E - Code source

chapitre2zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 11 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

III - Fermer notre fenecirctre gracircce aux boutons

III-A - Aperccedilu

III-B - Les boutons poussoir

Maintenant que notre programme se termine proprement il est plus convivial de proposer agrave lutilisateur un boutonpour quitter Pour creacuteer un bouton poussoir il existe plusieurs possibiliteacutes

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 premiegravere fonction creacutee un bouton qui peut servir pour contenir nimporte quel autre widget (label image) Si voussouhaitez creacuteer un bouton avec du texte dessus utilisez directement la seconde fonction qui prend en argument letexte agrave afficher Si vous souhaitez ajouter un raccourci clavier (accessible avec la touche Alt) la troisiegraveme fonctionpermet den speacutecifier un en faisant preacuteceacuteder une lettre (geacuteneacuteralement la premiegravere) dun underscore _ (si voussouhaitez afficher le caractegravere _ il faut en mettre deux) Enfin la derniegravere fonction permet dutiliser les Stock Itemsqui sont un ensemble deacuteleacutements preacutedeacutefinis par GTK+ pour les menus et barres doutils Le seul paramegravetre de cettefonction est le nom de leacuteleacutement et GTK+ se charge dafficher licocircne approprieacutee ainsi que le texte suivant la languechoisie et un raccourci

Cest bien sucircr cette derniegravere fonction que nous allons utiliser et ce le plus souvent possible Voici le code pour creacuteerun tel bouton

maincGtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_QUIT)

Pour obtenir tous les types de stocks items disponibles GtkStockItem

Bien sucircr comme pour la fenecirctre si lon veut voir quelque chose il faut demander agrave GTK+ dafficher notre widget

maincgtk_widget_show (p_button)

Mais pas seulement En effet il faut preacuteciser agrave GTK+ ougrave doit ecirctre afficheacute notre bouton Pour cela la classe GtkWindowest deacuteriveacutee de la classe GtkContainer qui est comme son nom le laisse penser un conteneur pour widget Pourajouter un widget il suffit de faire appel agrave la fonction gtk_container_add

void gtk_container_add (GtkContainer container GtkWidget widget)

Le premier paramegravetre de cette fonction est un GtkContainer or nous souhaitons passer notre fenecirctre qui est unGtkWidget pour ne pas avoir de problegravemes il faut utiliser le systegraveme de macro offert par GTK+ pour transtyper notreGtkWidget en GtkContainer (eh oui en C le polymorphisme a ses limites)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 12 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

maincgtk_container_add (GTK_CONTAINER (p_window) p_button)

Ce meacutecanisme de transtypage permet agrave GTK+ de veacuterifier que notre GtkWidget est bien compatible avec lutilisationque lon souhaite en faire En cas deacutechec GTK+ nous preacutevient en affichant un message dans la console

(gtk_boutonexe1044) Gtk-CRITICAL gtk_container_add assertion `GTK_IS_CONTAINER (container) failed

Pour finir il faut connecter notre bouton pour appeler notre fonction cb_quit lorsque lutilisateur clic dessus (ce quicorrespond agrave leacuteveacutenement clicked)

g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_quit) NULL)

Pour eacuteviter dappeler la fonction gtk_widget_show pour tous les widgets de notreapplication on peut se contenter dun seul appel agrave la fonction gtk_widget_show_all quipermet dafficher tous les widgets contenus dans celui passeacute agrave la fonction

maincinclude ltstdlibhgtinclude ltgtkgtkhgtinclude callbackh

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (cb_quit) NULL)

GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_QUIT) gtk_container_add (GTK_CONTAINER (p_window) p_button) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_quit) NULL)

Affichage de la fenetre principale gtk_widget_show_all (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

III-C - Code source

chapitre3zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 13 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IV - Comment afficher plusieurs widgets

IV-A - Aperccedilu

IV-B - Le problegraveme

Dans la partie preacuteceacutedente nous avons reacuteussi agrave afficher un bouton dans la fenecirctre de notre application Si vous avezessayeacute dajouter un second widget GTK+ agrave ducirc vous reacutepondre poliment

(gtk_boxexe492) Gtk-WARNING Attempting to add a widget with typeGtkButton to a GtkWindow but as a GtkBin subclass a GtkWindow can only containone widget at a time it already contains a widget of type GtkButton

Les plus anglophiles dentre vous auront compris que GTK+ naccepte pas lajout un second widget dans notre fenecirctretout simplement parce quil y en a deacutejagrave un et que la sous classe GtkBin (classe megravere de notre GtkWindow) ne peutcontenir quun seul widget

IV-C - La solutions

Pour contourner ce problegraveme il faut commencer par creacuteer un widget qui accepte den contenir plusieurs autrespour ensuite y ajouter tout ce dont nous avons besoin Pour linstant nous utiliserons quun seul widget (il existetrois classes qui permettent ceci) il sagit des GtkBox Il sagit de la meacutethode que jutilise le plus souvent Ce nestpeut-ecirctre pas la plus simple agrave maicirctriser mais elle extrecircmement souple et puissante Elle consiste agrave creacuteer une boicirctepuis agrave y ajouter les widgets les uns apregraves les autres (soit au deacutebut soit agrave la fin) Il existe deux classes heacuteritant deGtkBox les GtkVBox qui empilent les widgets dans le sens vertical et les GtkHBox qui font de mecircme mais dansle sens horizontal Les fonctions pour manipuler ces deux classes sont les mecircmes seule la fonction pour les creacuteerportent un nom diffeacuterent

GtkWidget gtk_vbox_new (gboolean homogeneous gint spacing)GtkWidget gtk_hbox_new (gboolean homogeneous gint spacing)

Le paramegravetre homogeneous permet de reacuteserver pour chaque widget une zone de taille identique (zone que le widgetnest pas obligeacute de remplir) et spacing permet dajouter une bordure en pixels (espacement autour de la GtkBox)Ensuite il suffit dajouter les diffeacuterents widgets gracircce aux fonctions

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)

Qui ajoutent reacuteciproquement le widget child au deacutebut et agrave la fin de box Le paramegravetre expand permet au widget davoirle plus de place possible (si le paramegravetre homogeneous vaut TRUE cette option a aucun effet) Si plusieurs widgetont ce paramegravetre agrave TRUE ils se partagent de faccedilon eacutegale lespace Loption fill permet au widget de remplir toutlespace qui lui ait reacuteserveacute

Pour reacuteellement comprendre linfluence de ces paramegravetres il faut faire des tests en modifiant un agrave un chaqueparamegravetre et observer les effets dun redimentionnement de la fenecirctre principale

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 14 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Le plus gecircnant avec cette meacutethode cest quil faut jongler entre les GtkHBox et les GtkVBox en les imbriquant pourobtenir le reacutesultat souhaiter nheacutesitez pas agrave utiliser une feuille et un crayon )

Pour en revenir agrave notre eacutediteur de texte nous allons preacuteparer notre application agrave contenir les futurs widgetsNous utilisons un GtkVBox pour lensemble des widgets (il sagit de la boicircte principale qui pourra contenir dautresGtkContainer selon nos besoins)

maincinclude ltstdlibhgtinclude ltgtkgtkhgtinclude callbackh

int main (int argc char argv) GtkWidget p_window = NULL GtkWidget p_main_box = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (cb_quit) NULL)

Creation du conteneur principal p_main_box = gtk_vbox_new (FALSE 0) gtk_container_add (GTK_CONTAINER (p_window) p_main_box)

Creation du bouton Quitter GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_QUIT) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_quit) NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_button FALSE FALSE 0)

Affichage de la fenetre principale gtk_widget_show_all (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

IV-D - Code source

chapitre4zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 15 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

V - Afficher le contenue dun fichier

V-A - Aperccedilu

Cliquez pour agrandir

V-B - Saisir du texte

Les choses seacuterieuses vont commencer il sagit de mettre en place le widget qui va nous permettre dafficher etdeacutediter du texte Il sagit de la classe GtkTextView Gracircce agrave GTK+ la mise en place est toujours aussi simple

mainc GtkWidget p_text_view = NULL Creation de la zone de texte p_text_view = gtk_text_view_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_text_view TRUE TRUE 0)

Comme il sagit de la partie centrale de notre application nous demandons agrave ce quelle prenne le plus de placepossible (gracircce agrave la fonction gtk_box_pack_start)

Puisque nous voulons afficher les boutons en dessous de la zone de texte il faut ajouter ce morceau de code avantcelui creacuteant le bouton

V-C - Ouvrir un fichier

Maintenant nous avons une belle zone de texte il faut la remplir avec le contenu dun fichier Pour ce faire nousallons commencer par ajouter un bouton ouvrir

mainc Creation du bouton Ouvrir GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_OPEN) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_open) p_text_view) gtk_box_pack_start (GTK_BOX (p_main_box) p_button FALSE FALSE 0)

Si vous exeacutecutez le programme maintenant (3) vous remarquerez que les boutons sont ajouteacutes les uns en dessousdes autres ce qui diminue la zone de saisie (avec deux boutons ce nest pas gecircnant mais au bout dune dizaineccedila risque decirctre probleacutematique) Pour pallier ce problegraveme nous allons utiliser un nouveau style de GtkBox lesGtkButtonBox qui sont preacutevus pour contenir des boutons (ccedila tombe plutocirct bien D) Donc pour eacuteviter de diminuerla zone de saisie et comme nous avons de la place en largueur nous allons utiliser un GtkHButtonBox qui va ecirctreinclus dans la p_main_box Voici les modifications agrave effectuer

mainc GtkWidget p_button_box = NULL Creation du conteneur pour les boutons p_button_box = gtk_hbutton_box_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_button_box FALSE FALSE 0)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 16 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc gtk_box_pack_start (GTK_BOX (p_button_box) p_button FALSE FALSE 0) gtk_box_pack_start (GTK_BOX (p_button_box) p_button FALSE FALSE 0)

Maintenant il nous reste plus quagrave creacuteer la fonction cb_open dans le fichier callbackc pour linstant nous nouscontenterons douvrir toujours le mecircme fichier nous verrons plus tard comment laisser le choix agrave lutilisateur

callbackcdefine DEFAULT_FILE mainc

void cb_open (GtkWidget p_widget gpointer user_data) open_file (DEFAULT_FILE GTK_TEXT_VIEW (user_data))

Parametre inutilise (void)p_widget

Vous aurez compris que lon va deacuteleacuteguer tout le travail agrave la fonction open_file qui devra ouvrir le fichier dont le nomest passeacute en premier paramegravetre pour lafficher dans le GktTextView

Jai fait ce choix pour deux raisons le code dune fonction callback peut ecirctre tregraves conseacutequent (surtout si lon souhaitequelle affiche une boicircte de dialogue) et aussi parce que cb_open nest peut ecirctre pas la seule fonction agrave copierun fichier dans un GtkTextView (par exemple lors de la creacuteation dun nouveau fichier lon peut vouloir copier unsquelette de fichier)

Pour copier notre fichier plutocirct que dutiliser la fonction fgets nous allons nous servir de la glib (4) qui proposela fonction

gboolean g_file_get_contents (const gchar filename gchar contents gsize length GError error)

Qui nous renvoit le contenu du fichier nommeacute filename dans le tampon contents Il est possible de reacutecupeacuterer lenombre de caractegraveres copieacutes et retourne TRUE en cas de succegraves sinon FALSE et dans ce cas une structure de typeGError est creacutee pour en savoir plus sur le type derreur rencontreacute

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView else print_warning (Impossible douvrir le fichier sn file_name)

Je pense quun certain nombre dexplications simpose (surtout si je vais trop vite nheacutesitez pas agrave marrecircter )

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 17 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

bull g_return_if_fail est une macro qui peut ecirctre compareacutee agrave assert sauf quelle se contente de sortir de la fonctionsi lexpression passeacutee en paramegravetre est fausse Cest une meacutethode pratique pour veacuterifier la validiteacute desparamegravetres (si la fonction doit retourne une valeur utiliseacute plutocirct g_return_val_if_fail qui prend un secondparamegravetre la valeur agrave retourner)

bull Ensuite on essaie de reacutecupeacuterer le contenu de notre fichier

bull Si cela eacutechoue nous le signalons agrave lutilisateur agrave laide de la fonction print_warning

bull Le type gchar est une redeacutefinition du type char par la glib (il en va de mecircme pour tous les autres types du C)privileacutegiez ces types lorsque vous utilisez des fonctions de cette bibliothegraveques

Mais quest-ce donc cette fonction print_warning Cest une fonction que nous allons creacuteer semblable agrave printf quisignalera agrave lutilisateur quune erreur non critique est survenue Comme nous navons pas encore abordeacute les boicirctesde dialogue pour afficher un message il sagira pour linstant dune simple redeacutefinition de printf Pendant que noussommes dans laffichage des messages nous allons aussi creacuteer deux fonctions print_info et print_error qui vontrespectivement afficher un message dinformation et un message derreur critique (ce qui entraicircne la terminaison duprogramme) tout ceci dans un nouveau fichier errorc

errorhifndef H_ERRORdefine H_ERROR

void print_info (char )void print_warning (char )void print_error (char )

endif not H_ERROR

errorcinclude ltstdarghgtinclude ltstdiohgtinclude ltstdlibhgtinclude errorh

void print_info (char format ) va_list va

va_start (va format) printf (Information ) vprintf (format va) printf (n)

void print_warning (char format ) va_list va

va_start (va format) fprintf (stderr Erreur ) vfprintf (stderr format va) fprintf (stderr n)

void print_error (char format ) va_list va

va_start (va format) fprintf (stderr Erreur fatale ) vfprintf (stderr format va) fprintf (stderr n) exit (EXIT_FAILURE)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 18 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

Pour en finir avec louverture dun fichier il nous reste agrave copier contents dans le GtkTextView En fait le GtkTextViewne gegravere que la forme pour modifier le contenu il faut passer par les GtkTextBuffer Commenccedilons donc par reacutecupeacutererce fameux GtkTextBuffer

callbackc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (p_text_view)

Et pour finir on utilise la fonction

void gtk_text_buffer_insert (GtkTextBuffer buffer GtkTextIter iter const gchar text gint len)

Reacutecapitulons buffer est le GtkTextBuffer que lon vient de reacutecupeacuterer text cest le texte agrave afficher et len la taille dece dernier (ou -1 sil sagit dune chaicircne de caractegraveres au sens du langage C)

Mais quest-ce donc ce GtkTextIter On peut voir cela comme un curseur virtuel qui indique la position agrave laquelleeffectuer linsertion de texte dans le GtkTextBuffer (5) Allons voir ce que la documentation peut nous apprendreagrave leur sujet (6)

typedef struct GtkTextIter is an opaque datatype ignore all these fields Initialize the iter with gtk_text_buffer_get_iter_ functions GtkTextIter

Voilagrave on a notre solution suffit de rechercher les fonctions commenccedilant par gtk_text_buffer_get_iter_ voici la liste

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)

La fonction gtk_text_buffer_get_iter_at_line fait parfaitement laffaire

callbackc GtkTextIter iter

gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1)

Cependant si vous ne voulez pas avoir de problegravemes avec le codage des caractegraveres il vaut mieux convertir le codagelocal vers utf8 Voici le reacutesultat final

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 19 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gchar utf8 = NULL GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_text_buffer_insert (p_text_buffer ampiter utf8 -1) g_free (utf8) utf8 = NULL

V-D - La petite touche finale

Pour finir cette laborieuse partie sur une petite touche estheacutetique nous allons demander agrave GTK+ de nous lancerlapplication en plein eacutecran Pour se faire il suffit dajouter lors de la creacuteation de la fenecirctre principale

maincgtk_window_maximize (GTK_WINDOW (p_window))

On peut mecircme se permettre une pointe dexcentriciteacute en modifiant le titre de notre fenecirctre

maincgtk_window_set_title (GTK_WINDOW (p_window) Editeur de texte en GTK+)

V-E - Code source

chapitre5zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 20 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VI - Choisir un fichier

VI-A - Aperccedilu

Cliquez pour agrandir

VI-B - Utilisation dun GtkFileChooserFile

Jusquagrave preacutesent lutilisateur navait pas le choix quant au fichier agrave ouvrir heureusement GTK+ vient agrave notre aide gracircceau widget GtkFileChooserFile qui est tout simplement une boicircte de dialogue qui propose agrave lutilisateur de seacutelectionnerun fichier dans son arborescence disque

Commenccedilons par creacuteer notre boicircte de dialogue dans la fonction cb_open

callbackcvoid cb_open (GtkWidget p_widget gpointer user_data) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Ouvrir un fichier NULL GTK_FILE_CHOOSER_ACTION_OPEN GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_OPEN GTK_RESPONSE_ACCEPT NULL)

Cette fonction neacutecessite le titre de la boicircte de dialogue une fenecirctre parente le type daction (ici on souhaite ouvrir unfichier GTK+ autorisera lutilisateur agrave seacutelectionner uniquement les fichiers existants) Pour finir il sagit dun couple devaleurs GTK_STOCK_ITEMGTK_STOCK_RESPONSE qui permet de creacuteer un bouton utilisant le stock ID speacutecifieacuteet lorsque celui-ci est cliqueacute la fonction servant agrave lancer la boicircte de dialogue retournera le reacuteponse ID correspondantIl existe une seacuterie de valeurs deacutefinies par GTK+ quil est conseilleacute dutiliser

typedef enum GTK returns this if a response widget has no response_id or if the dialog gets programmatically hidden or destroyed GTK_RESPONSE_NONE = -1

GTK wont return these unless you pass them in as the response for an action widget They are for your convenience GTK_RESPONSE_REJECT = -2 GTK_RESPONSE_ACCEPT = -3

If the dialog is deleted GTK_RESPONSE_DELETE_EVENT = -4

These are returned from GTK dialogs and you can also use them yourself if you like GTK_RESPONSE_OK = -5 GTK_RESPONSE_CANCEL = -6 GTK_RESPONSE_CLOSE = -7 GTK_RESPONSE_YES = -8

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 21 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GTK_RESPONSE_NO = -9 GTK_RESPONSE_APPLY = -10 GTK_RESPONSE_HELP = -11 GtkResponseType

Nous indiquons la fin des couples stock idreacuteponse id avec la valeur NULL

Une fois la boicircte de dialogue creacuteee on demande agrave GTK+ de lafficher gracircce agrave la fonction gtk_dialog_run puis onreacutecupegravere sa valeur de retour qui correspond au bouton cliqueacute par lutilisateur

callbackc if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

Ici ce qui nous inteacuteresse cest lorsque que lutilisateur clique sur le bouton ouvrir (donc gtk_dialog_run renvoieGTK_RESPONSE_ACCEPT) dans ce cas il nous suffit de reacutecupeacuterer le nom du fichier seacutelectionneacute puis de louvrir

callbackc gchar file_name = NULL

file_name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) open_file (file_name GTK_TEXT_VIEW (user_data)) g_free (file_name) file_name = NULL

Pour finir dans tous les cas on noublie pas de deacutetruire la boicircte de dialogue

callbackc gtk_widget_destroy (p_dialog)

Et voilagrave le travail lutilisateur peut ouvrir le fichier quil souhaite

VI-C - Code source

chapitre6zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 22 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VII - Interlude

Avant daller plus loin dans lameacutelioration de linterface de notre eacutediteur il est neacutecessaire de modifier sonfonctionnement interne (ne vous inquieacutetez je nai pas dit chambouler) en effet souvenez-vous dans lintroduction jaieacutevoqueacute la possibiliteacutes douvrir plusieurs documents gracircce agrave un systegraveme donglets Pour cela il faut sauvegarder lesproprieacuteteacutes de chaque document ouvert Pris agrave temps ce genre de modification nest pas trop lourde mais si nousattendons cela risque de devenir un vrai casse tecircte

Pour cela nous allons utiliser une structure de donneacutee pour chaque document ouvert qui devra garder en meacutemoirele chemin complet du fichier (ou NULL si le document nest pas encore sauvegarder) sil agrave eacutetait modifier depuis laderniegravere sauvegarde et le GtkTextView qui sert agrave son affichage Voici donc la structure qui va nous servir

documenthtypedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

Sachant que nous serons ameneacute agrave stocker plusieurs occurrences de cette structure il serait bon de reacutefleacutechir degravesmaintenant agrave la structure de donneacutee agrave utiliser pour les stocker La premiegravere ideacutee qui vient agrave lesprit est un tableaualloueacute dynamiquement cependant lutilisateur peut souhaiter fermer un document qui se trouve au milieu on estalors obligeacute de deacutecaler toutes les cellules en amont Dans ce cas il parait naturel dutiliser une liste chaicircneacutee Parchance la glib propose une bibliothegraveque de gestion des listes chaicircneacutees cela nous fera gagner du temps le momentvenu Pour linstant on se contente de creacuteer une structure de donneacutees qui contiendra tous les documents ouverts(stockeacutee dans une GList) et un pointeur sur le document actif (actuellement comme nous navons quun documentouvert en mecircme temps on manipulera uniquement ce pointeur)

documenthtypedef struct GList tous document_t actif docs_t

Maintenant se pose le problegraveme de savoir comment transmettre cette structure On pourrait se servir du paramegravetreuser_data preacutesent dans toutes les fonctions callback mais certaines fonctions utilise deacutejagrave ce paramegravetre (la fonctioncb_open par exemple) il faudrait creacuteer un champs suppleacutementaire dans notre structure documents_s Une solutionplus simple est de creacuteer une variable globale agrave lensemble du programme Ceux qui passe reacuteguliegraverement sur le forumC savent que cest fortement deacuteconseilleacute mais ici nous nous trouvons dans lune des rares exceptions agrave la regravegle Detoute faccedilon cela revient au mecircme que de passer ladresse de notre structure agrave toutes les fonctions callback Nousdeacutefinissons donc un nouveau fichier den-tecircte

documenthifndef H_DOCUMENTdefine H_DOCUMENT

include ltgtkgtkhgt

typedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 23 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

documenthtypedef struct GList tous document_t actif docs_t

extern docs_t docs

endif not H_DOCUMENT

Et dans le fichier mainc

maincinclude documenth

docs_t docs = NULL NULL

Pour linstant la seule fonction qui modifie leacutetat dun document est la fonction open_file il faut donc inclure documenthdans callbackc et modifier leacutegegraverement la fonction pour enregistrer le document ouvert

callbackc if (g_file_get_contents (file_name ampcontents NULL NULL)) Pour linstant il faut allouer la memoire par la suite on modifira simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = g_strdup (file_name) Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = p_text_view Le document vient detre ouvert il nest donc pas modifie docsactif-gtsauve = TRUE

Ne soyez pas choqueacute si je ne teste pas le retour de la fonction g_malloc pour veacuterifier quilnest pas NULL En effet cette derniegravere met fin agrave lapplication si lallocation eacutechoue

VII-A - Code source

chapitre7zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 24 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VIII - Sauvegarder les modification

VIII-A - Aperccedilu

Cliquez pour agrandir

VIII-B - Enregistrer

Avant de pouvoir sauvegarder un document il faut quil soit modifieacute Comment savoir que le contenu du fichier a eacuteteacutemodifier Gracircce au signal changed du GtkTextBuffer que nous interceptons gracircce agrave la fonction cb_modifie

mainc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (p_text_view)) g_signal_connect (G_OBJECT (p_text_buffer) changed G_CALLBACK (cb_modifie) NULL)

Cette derniegravere modifie simplement le champ sauve du document

callbackcvoid cb_modifie (GtkWidget p_widget gpointer user_data) if (docsactif) docsactif-gtsauve = FALSE

Pour la sauvegarde il faut distinguer deux cas soit il sagit de la premiegravere sauvegarde du fichier il faut alors demanderle nom du fichier agrave lutilisateur (cela ressemble fortement agrave louverture dun fichier) soit le fichier est deacutejagrave preacutesent surle disque il suffit de remplacer son contenu par celui du GtkTextViewer Nous avons convenu quun fichier qui neacutetaitpas encore enregistreacute avait sa proprieacuteteacute chemin agrave NULL

Bien sucircr cela na lieu que si un fichier est ouvert et quil a eacuteteacute modifieacute depuis sa derniegravere sauvegarde

callbackcvoid cb_save (GtkWidget p_widget gpointer user_data) if (docsactif) if (docsactif-gtsauve) Le fichier na pas encore ete enregistre if (docsactif-gtchemin) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Sauvegarder le fichier NULL GTK_FILE_CHOOSER_ACTION_SAVE GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_SAVE GTK_RESPONSE_ACCEPT NULL) if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 25 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc docsactif-gtchemin = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) gtk_widget_destroy (p_dialog) Soit le fichier a deja ete enregistre soit lutilisateur vient de nous fournir son nouvel enplacement on peut donc lenregistrer if (docsactif-gtchemin) else print_warning (Aucun document ouvert)

Il nous reste plus quagrave reacutecupeacuterer le contenu du GtkTextViewer et le copier dans le fichier chemin sans oublier dereconvertir le texte dans le codage local

callbackc FILE fichier = NULL

fichier = fopen (docsactif-gtchemin w) if (fichier) gchar contents = NULL gchar locale = NULL GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) contents = gtk_text_buffer_get_text (p_text_buffer ampstart ampend FALSE) locale = g_locale_from_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL fprintf (fichier s locale) g_free (locale) locale = NULL fclose (fichier) fichier = NULL docsactif-gtsauve = TRUE else print_warning (Impossible de sauvegarder le fichier s docsactif-gtchemin)

Le dernier paramegravetre de la fonction gtk_text_buffer_get_text est mis agrave FALSE car nous ne voulons pas enregistrerles caractegraveres invisibles preacutesent dans le GtkTextBuffer Ces caractegraveres servent agrave mettre en forme le texte (taillecouleur) nous pourrions creacuteer un nouveau format de fichier pour enregistrer la mise en forme

VIII-C - Enregistrer sous

Pour enregistrer notre document sous un autre nom il suffit de faire croire agrave cb_save que le document na pas encoreeacutetait enregistreacute tout simplement en changeant chemin agrave NULL et sauve agrave FALSE

callbackcvoid cb_saveas (GtkWidget p_widget gpointer user_data)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 26 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (docsactif) document_t tmp = docsactif

docsactif-gtchemin = NULL docsactif-gtsauve = FALSE cb_save (p_widget user_data) if (docsactif-gtsauve) (docsactif) = tmp else print_warning (Aucun document ouvert)

Il ne faut pas oublier que lutilisateur peut annuler lenregistrement de ce fait nous sauvegardons leacutetat du documentet si la sauvegarde na pas eu lieu on le restaure

VIII-D - Code source

chapitre8zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 27 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IX - Creacuteer un nouveau document

IX-A - Aperccedilu

Cliquez pour agrandir

IX-B - Nouveau fichier

Maintenant que lutilisateur peut ouvrir et fermer un fichier il est inteacuteressant de lui donner la possibiliteacute den creacuteerun nouveau Je ne reviens pas sur la creacuteation du bouton (ccedila devrait deacutejagrave ecirctre fait D) passons directement agrave lafonction cb_new

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) Pour linstant il faut allouer la memoire par la suite on modifiera simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = NULL Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = GTK_TEXT_VIEW (user_data) Le document vient detre creer il nest donc pas modifie docsactif-gtsauve = TRUE gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Je ne sais pas vous mais pour ma part jai fait un copiercoller de la fonction open_file Et oui ouvrir un document peutse reacutesumer agrave creacuteer un document vide puis remplir le GtkTextView avec le fichier souhaiteacute On peut donc simplifiernotre fonction open_file ainsi

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

cb_new (NULL p_text_view) gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE) p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1) Nous sommes obliges de remetre sauve a TRUE car linsertion du contenu du fichier dans le GtkTextView a appele cb_modfie docsactif-gtsauve = TRUE else print_warning (Impossible douvrir le fichier sn file_name)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 28 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc

Cest beau la factorisation du code Par contre nous sommes obligeacutes de remettre sauve agrave TRUE car nous avonsmodifieacute le GtkTextBuffer

IX-C - Code source

chapitre9zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 29 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

X - Fermer

X-A - Aperccedilu

Cliquez pour agrandir

X-B - Fermer un fichier

Maintenant que nous allouons de la meacutemoire il faut la libeacuterer agrave un endroit Logiquement cela va ecirctre fait agrave la fermeturedu document en guise dexercice je vous laisse creacuteer le bouton dans notre boicircte agrave bouton

Allez je vous aide le stock id correspondant est GTK_STOCK_CLOSE

Voilagrave maintenant si tout cest bien passeacute vous devriez ecirctre arriveacute dans le fichier callbackc avec quelque choseressemblant agrave

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data)

Lorsque lon ferme un document il faut vider le GtkTextView (avec les onglets on se contentera de le supprimer)pour cela il faut reacutecupeacuterer le deacutebut et la fin du GtkTextBuffer et demander agrave GTK+ de supprimer tout ce qui ce trouveentre les deux iteacuterateurs

callbackc Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) gtk_text_buffer_delete (p_text_buffer ampstart ampend) else print_warning (Aucun document ouvert)

Bien sucircr il ne faut pas oublier de libeacuterer la meacutemoire

callbackc g_free (docsactif-gtchemin) docsactif-gtchemin = NULL docsactif-gtp_text_view = NULL g_free (docsactif) docsactif = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 30 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour symboliser la fermeture dun document nous deacutesactivons le GtkTextView lors de la fermeture (ne pas oublierde le faire aussi dans mainc)

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) FALSE)

Et nous le reacuteactivons lors de louverture si celle si reacuteussie

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Lorsque lutilisateur quitte lapplication il faut bien sucircr fermer le document sil y en a un ouvert

void cb_quit (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data) gtk_main_quit()

Et aussi lorsquil creacuteeacute un nouveau document (et par conseacutequent lorsquil ouvre un fichier puisque lon fait appel agravecb_new)

void cb_new (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data)

X-C - Enregistrer avant de fermer

Si le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde geacuteneacuteralement le programme le signale agrave lutilisateur etlui propose de sauvegarder ou dannuler la fermeture Pour se faire nous devons modifier la fonction cb_close avantde fermer le document nous allons afficher une boicircte de dialogue

Pour creacuteer une boicircte de dialogue simplement il existe la classe GtkDialog et comme nous avons besoin de boutons(pour que lutilisateur fasse son choix) nous allons creacuteer notre boicircte avec la fonction

GtkWidget gtk_dialog_new_with_buttons (const gchar title GtkWindow parent GtkDialogFlags flags const gchar first_button_text )

Nous retrouvons les mecircmes options que pour le GtkFileChooserDialog mis agrave part option du type GtkDialogFlags

typedef enum GTK_DIALOG_MODAL = 1 ltlt 0 appel gtk_window_set_modal (win TRUE) GTK_DIALOG_DESTROY_WITH_PARENT = 1 ltlt 1 appel gtk_window_set_destroy_with_parent () GTK_DIALOG_NO_SEPARATOR = 1 ltlt 2 Pas de barre de separation au dessus des boutons GtkDialogFlags

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 31 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Nous nous contenterons de rendre notre fenecirctre modale (7)

Pour avoir accegraves agrave notre fenecirctre principale nous ajoutons un champs p_main_window agrave notre structure globaledocs_t que nous initialisons dans la fonction main

mainc docsp_main_window = GTK_WINDOW (p_window)

Il nous reste plus qua creacuteer notre boicircte de dialogue avec trois boutons Oui Non Annuler

callbackc if (docsactif-gtsauve) GtkWidget p_dialog = NULL

p_dialog = gtk_dialog_new_with_buttons (Sauvegarder docsp_main_window GTK_DIALOG_MODAL GTK_STOCK_YES GTK_RESPONSE_YES GTK_STOCK_NO GTK_RESPONSE_NO GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL NULL)

Nous obtenons donc une structure de type GtkDialog

typedef struct GtkWidget vbox GtkWidget action_area GtkDialog

Nous remarquons que cette structure contient deux membres qui permettent dacceacuteder agrave une GtkBox ougrave nous allonsajouter le contenu de la fenecirctre et agrave la partie contenant les boutons

Ensuite la construction de la fenecirctre est identique agrave celle de la fenecirctre principale ici nous nous contenterons dajouterun GtkLabel

callbackc GtkWidget p_label = NULL p_label = gtk_label_new (Voulez-vous sauvegarder les modifications ) gtk_box_pack_start (GTK_BOX (GTK_DIALOG (p_dialog)-gtvbox) p_label TRUE TRUE 0)

Une fois notre fenecirctre precircte il suffit de faire appel agrave la fonction gtk_dialog_run qui va afficher notre GtkDialog et nousretourner le reacuteponse id correspondant au bouton cliqueacute par lutilisateur

callbackc switch (gtk_dialog_run (GTK_DIALOG (p_dialog))) case GTK_RESPONSE_YES cb_save (p_widget user_data) break case GTK_RESPONSE_NO break case GTK_RESPONSE_CANCEL gtk_widget_destroy (p_dialog) return break

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 32 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc gtk_widget_destroy (p_dialog)

Si lutilisateur clique sur non on ne fait rien (le document sera simplement fermeacute) sur oui on enregistre avant defermer et pour finir sil annule on quitte la fonction

X-D - Code source

chapitre10zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 33 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XI - Les barres de deacutefilement

XI-A - Aperccedilu

Cliquez pour agrandir

XI-B - Ajouter des barres de deacutefilement

Apregraves le dernier chapitre quelque peu laborieux voici une partie plus simple mais qui va rendre notre applicationplus pratique En effet si vous avez essayeacute douvrir un fichier de grande taille vous avez pu remarquer que pourpouvoir lire la fin du fichier il fallait utiliser les touches du clavier pas tregraves convivial

Pour rendre la navigation plus aiseacutee on utilise des barres de deacutefilement

mainc GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_scrolled_window TRUE TRUE 0)

Creation de la zone de texte gtk_container_add (GTK_CONTAINER (p_scrolled_window) p_text_view)

Le constructeur de notre GtkScrolledWindow prend en argument deux GtkAdjustment qui permettent de deacutefinirdiffeacuterentes proprieacuteteacutes de la barre de deacutefilement (taille dune page la position de deacutepart) nous laissons GTK+ faireen passant NULL

Cest un bon deacutebut mais estheacutetiquement on peut faire mieux mecircme sil nest pas utile davoir une barre de deacutefilementelle est quand mecircme afficheacutee On peut demander agrave GTK+ de les afficher que si cela est neacutecessaire

mainc gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC)

En fait nous avons de la chance car la classe GtkTextView fait partie des widget qui supporte de faccedilon native les barresde deacutefilement Comment le savoir Ce genre de widget possegravede une ou deux proprieacuteteacutes de type GtkAdjustment (unepour la barre verticale lautre pour la barre horizontale) Actuellement seulement trois classes en sont capables lesGtkTextView les GtkTreeView et les GtkLayout

Comment faire pour les autres widgets Il faut passer par une classe adaptateur GtkViewport afin de creacuteer lesGtkAdjustment

XI-C - Code source

chapitre11zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 34 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XII - Les menus

XII-A - Aperccedilu

Cliquez pour agrandir

XII-B - Creacuteation du menu

Pour simplifier nous avons utiliseacute des boutons pour permettre agrave lutilisateur de creacuteer un document ouvrir un fichierMais il est plus courant dutiliser un menu pour afficher ces options GTK+ propose trois maniegraveres de creacuteer un menu

bull GtkItemFactory cette meacutethode est obsolegravete depuis la version 24 de GTK+

bull GtkUIManager cest ce quon appel une usine agrave gaz pour en savoir plus vous pouvez vous reporter aututoriel Utilisation de GtkUIManager

bull GtkMenu cest ce widget que nous allons eacutetudier il permet de creacuteer un menu manuellement (agrave lopposeacute deGtkUIManager)

Un menu selon GTK+ est composeacute de plusieurs eacuteleacutements

bull GtkMenuBar la barre de menu elle-mecircme

bull GtkMenu la partie deacuteroulante qui contient les diffeacuterents eacuteleacutements

bull GtkMenuItem cest sur ce widget que lutilisateur clique pour lancer une action

Pour commencer faisons linventaire de ce que nous avons besoin

bull Un GtkMenuBar qui sert de base au menu

bull Un GtkMenu pour commencer nous nous aurons dun menu Fichier

bull Six GtkMenuItem pour remplacer nos six boutons

Commenccedilons par la creacuteation du menu nous mettons ce code dans un nouveau fichier dont seul la fonction menu_newsera accessible

menucGtkMenuBar menu_new (gpointer user_data) GtkWidget p_menu_bar = NULL

p_menu_bar = gtk_menu_bar_new () return GTK_MENU_BAR (p_menu_bar)

Le paramegravetre user_data nous servira lors de la connexion des callbacks (nous en avons besoin pour les fonctionscb_new et cb_open)

Ensuite nous allons creacuteer notre sous menu Fichier

menuc Menu Fichier

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 35 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

menuc GtkWidget p_menu = NULL GtkWidget p_menu_item = NULL

p_menu = gtk_menu_new () p_menu_item = gtk_menu_item_new_with_mnemonic (_Fichier) gtk_menu_item_set_submenu (GTK_MENU_ITEM (p_menu_item) p_menu) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu_bar) p_menu_item) return GTK_MENU_BAR (p_menu_bar)

Un sous menu est en fait un GtkMenuItem auquel on assigne un GtkMenu Il faut bien sucircr terminer la creacuteation dusous-menu en lajoutant agrave la barre de menu

Pour finir nous creacuteons les eacuteleacutements du menu les GtkItemMenu Il existe plusieurs types deacuteleacutements (comparableaux diffeacuterents types de bouton) pour commencer nous nutiliserons que le type de base Comme cette opeacuteration estreacutepeacutetitive nous allons creacuteer une fonction pour le faire

menucstatic void menu_item_new (GtkMenu p_menu const gchar title GCallback callback gpointer user_data) GtkWidget p_menu_item = NULL

p_menu_item = gtk_menu_item_new_with_mnemonic (title) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu) p_menu_item) g_signal_connect (G_OBJECT (p_menu_item) activate callback user_data)

Pour permettre agrave lutilisateur dacceacuteder aux diffeacuterents eacuteleacutements du menu agrave laide de la touche ltAltgt nous utilisonsdes mneacutemoniques par exemple pour quitter leacutediteur il suffit de faite Alt+F puis Q Et voici le code pour creacuteer nossix eacuteleacutements du menu

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau G_CALLBACK (cb_new) user_data) menu_item_new (GTK_MENU (p_menu) _Ouvrir G_CALLBACK (cb_open) user_data) menu_item_new (GTK_MENU (p_menu) _Enregistrer G_CALLBACK (cb_save) user_data) menu_item_new (GTK_MENU (p_menu) Enregistrer _sous G_CALLBACK (cb_saveas) user_data) menu_item_new (GTK_MENU (p_menu) _Fermer G_CALLBACK (cb_close) user_data) menu_item_new (GTK_MENU (p_menu) _Quitter G_CALLBACK (cb_quit) user_data)

Voilagrave notre menu est creacuteeacute il nous reste plus quagrave linteacutegrer agrave notre fenecirctre

mainc gtk_box_pack_start (GTK_BOX (p_main_box) GTK_WIDGET (menu_new (p_text_view)) FALSE FALSE 0)

Le problegraveme cest que nous avons besoin de passer le GtkTextView lors de la creacuteation du menu (qui est utiliseacute par lesfonctions cb_new et cb_open) or celui-ci est creacuteeacute apregraves le menu (puisque nous creacuteons les widgets dans lordre ougrave ilfaut les inteacutegrer agrave linterface (8) ) nous devons creacuteer le GtkTextView (seul lappel agrave gtk_text_view_new est deacuteplaceacute)

XII-C - Code source

chapitre12zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 36 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIII - Les barres doutils

XIII-A - Aperccedilu

Cliquez pour agrandir

XIII-B - Creacuteation dune barre doutils

La creacuteation dune barre doutils ressemble fort agrave celle dun menu en plus simple puisquil ny a pas de sous menu on creacutee notre barre doutils (gtk_toolbar_new) puis les eacuteleacutements de la barre pour cela on utilise des boutons(gtk_tool_button_new_from_stock) que lon inseacutere dans la barre (gtk_toolbar_insert) Pas conseacutequent notre fichierbarreoutilsc ressemble agrave menuc

barreoutilscinclude ltgtkgtkhgtinclude callbackhinclude barreoutilsh

static void toolbar_item_new (GtkToolbar const gchar GCallback gpointer)

GtkToolbar toolbar_new (gpointer user_data) GtkWidget p_toolbar = NULL

p_toolbar = gtk_toolbar_new () toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_NEW G_CALLBACK (cb_new) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_OPEN G_CALLBACK (cb_open) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE G_CALLBACK (cb_save) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE_AS G_CALLBACK (cb_saveas) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_CLOSE G_CALLBACK (cb_close) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_QUIT G_CALLBACK (cb_quit) user_data) return GTK_TOOLBAR (p_toolbar)

static void toolbar_item_new (GtkToolbar p_toolbar const gchar stock_id GCallback callback gpointer user_data) GtkToolItem p_tool_item = NULL

p_tool_item = gtk_tool_button_new_from_stock (stock_id) g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data) gtk_toolbar_insert (p_toolbar p_tool_item -1)

Le code nest pas complet car lorsque jexeacutecute le programme GTK+ affiche en plus des icocircnes le texte sous lesboutons Pour modifier cela il suffit dajouter une ligne de code

barreoutilsc gtk_toolbar_set_style (GTK_TOOLBAR (p_toolbar) GTK_TOOLBAR_ICONS)

Pourquoi gtk_tool_button_new_from_stock retourne un GtkToolItem et non un GtkWidgetcomme nous avons eacuteteacute habitueacute jusquagrave preacutesent Il sagit dune bizarrerie de GTK+ dontje ne connais pas la raison

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 37 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour anticiper un changement dinterface (dans GTK+ 30 peut ecirctre ) nous aurions pueacutecrire

Gtkwidget p_tool_item = NULL

p_tool_item = GTK_WIDGET (gtk_tool_button_new_from_stock (stock_id))g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data)gtk_toolbar_insert (p_toolbar GTK_TOOL_ITEM (p_tool_item) -1)

XIII-C - Code source

chapitre13zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 38 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIV - Les racourcis clavier

XIV-A - Aperccedilu

Cliquez pour agrandir

XIV-B - Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mneacutemoniques ces derniers permettent dacceacuteder agrave un eacuteleacutementseacutequentiellement alors que les raccourcis appellent une fonction si lutilisateur appuie simultaneacutement sur une ouplusieurs touches (geacuteneacuteralement de la forme ltModificateurgtTouche ougrave Modificateur repreacutesente les touches ShiftAlt et Control) Ce raccourci peut ecirctre attacheacute agrave un eacuteleacutement du menu mais ceci nest pas obligatoire

Les raccourcis sont regroupeacutes en groupe dans un GtkAccelGroup quil faut commencer par creacuteer

raccourciscinclude ltgtkgtkhgtinclude callbackhinclude raccourcish

GtkAccelGroup accel_group_new (gpointer user_data) GtkAccelGroup p_accel_group = NULL

p_accel_group = gtk_accel_group_new () return p_accel_group

Vous commencez agrave avoir lhabitude de cette organisation nous allons donc creacuteer une fonction qui va se chargerdajouter un raccourci au groupe

raccourciscstatic void accelerator_new (GtkAccelGroup p_accel_group const gchar accelerator const gchar accel_path GCallback callback gpointer user_data) guint key GdkModifierType mods GClosure closure = NULL

gtk_accelerator_parse (accelerator ampkey ampmods) closure = g_cclosure_new (callback user_data NULL) gtk_accel_group_connect (p_accel_group key mods GTK_ACCEL_VISIBLE closure) gtk_accel_map_add_entry (accel_path key mods)

La fonction gtk_accelerator_parse permet de deacutecomposer une chaicircne de caractegraveres de la forme ltControlgtF1 ouencore ltAltgtA en numeacutero de touche et modificateur

En plus des touches pour creacuteer un raccourci clavier nous avons besoin dune fonction agrave appeler lorsque lutilisateurappuie sur les touches speacutecifieacutees gtk_accel_group_connect attend une fonction du type GClosure regardons ladocumentation de gobject pour savoir agrave quoi cela correspond

typedef struct

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 11 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

III - Fermer notre fenecirctre gracircce aux boutons

III-A - Aperccedilu

III-B - Les boutons poussoir

Maintenant que notre programme se termine proprement il est plus convivial de proposer agrave lutilisateur un boutonpour quitter Pour creacuteer un bouton poussoir il existe plusieurs possibiliteacutes

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 premiegravere fonction creacutee un bouton qui peut servir pour contenir nimporte quel autre widget (label image) Si voussouhaitez creacuteer un bouton avec du texte dessus utilisez directement la seconde fonction qui prend en argument letexte agrave afficher Si vous souhaitez ajouter un raccourci clavier (accessible avec la touche Alt) la troisiegraveme fonctionpermet den speacutecifier un en faisant preacuteceacuteder une lettre (geacuteneacuteralement la premiegravere) dun underscore _ (si voussouhaitez afficher le caractegravere _ il faut en mettre deux) Enfin la derniegravere fonction permet dutiliser les Stock Itemsqui sont un ensemble deacuteleacutements preacutedeacutefinis par GTK+ pour les menus et barres doutils Le seul paramegravetre de cettefonction est le nom de leacuteleacutement et GTK+ se charge dafficher licocircne approprieacutee ainsi que le texte suivant la languechoisie et un raccourci

Cest bien sucircr cette derniegravere fonction que nous allons utiliser et ce le plus souvent possible Voici le code pour creacuteerun tel bouton

maincGtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_QUIT)

Pour obtenir tous les types de stocks items disponibles GtkStockItem

Bien sucircr comme pour la fenecirctre si lon veut voir quelque chose il faut demander agrave GTK+ dafficher notre widget

maincgtk_widget_show (p_button)

Mais pas seulement En effet il faut preacuteciser agrave GTK+ ougrave doit ecirctre afficheacute notre bouton Pour cela la classe GtkWindowest deacuteriveacutee de la classe GtkContainer qui est comme son nom le laisse penser un conteneur pour widget Pourajouter un widget il suffit de faire appel agrave la fonction gtk_container_add

void gtk_container_add (GtkContainer container GtkWidget widget)

Le premier paramegravetre de cette fonction est un GtkContainer or nous souhaitons passer notre fenecirctre qui est unGtkWidget pour ne pas avoir de problegravemes il faut utiliser le systegraveme de macro offert par GTK+ pour transtyper notreGtkWidget en GtkContainer (eh oui en C le polymorphisme a ses limites)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 12 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

maincgtk_container_add (GTK_CONTAINER (p_window) p_button)

Ce meacutecanisme de transtypage permet agrave GTK+ de veacuterifier que notre GtkWidget est bien compatible avec lutilisationque lon souhaite en faire En cas deacutechec GTK+ nous preacutevient en affichant un message dans la console

(gtk_boutonexe1044) Gtk-CRITICAL gtk_container_add assertion `GTK_IS_CONTAINER (container) failed

Pour finir il faut connecter notre bouton pour appeler notre fonction cb_quit lorsque lutilisateur clic dessus (ce quicorrespond agrave leacuteveacutenement clicked)

g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_quit) NULL)

Pour eacuteviter dappeler la fonction gtk_widget_show pour tous les widgets de notreapplication on peut se contenter dun seul appel agrave la fonction gtk_widget_show_all quipermet dafficher tous les widgets contenus dans celui passeacute agrave la fonction

maincinclude ltstdlibhgtinclude ltgtkgtkhgtinclude callbackh

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (cb_quit) NULL)

GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_QUIT) gtk_container_add (GTK_CONTAINER (p_window) p_button) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_quit) NULL)

Affichage de la fenetre principale gtk_widget_show_all (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

III-C - Code source

chapitre3zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 13 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IV - Comment afficher plusieurs widgets

IV-A - Aperccedilu

IV-B - Le problegraveme

Dans la partie preacuteceacutedente nous avons reacuteussi agrave afficher un bouton dans la fenecirctre de notre application Si vous avezessayeacute dajouter un second widget GTK+ agrave ducirc vous reacutepondre poliment

(gtk_boxexe492) Gtk-WARNING Attempting to add a widget with typeGtkButton to a GtkWindow but as a GtkBin subclass a GtkWindow can only containone widget at a time it already contains a widget of type GtkButton

Les plus anglophiles dentre vous auront compris que GTK+ naccepte pas lajout un second widget dans notre fenecirctretout simplement parce quil y en a deacutejagrave un et que la sous classe GtkBin (classe megravere de notre GtkWindow) ne peutcontenir quun seul widget

IV-C - La solutions

Pour contourner ce problegraveme il faut commencer par creacuteer un widget qui accepte den contenir plusieurs autrespour ensuite y ajouter tout ce dont nous avons besoin Pour linstant nous utiliserons quun seul widget (il existetrois classes qui permettent ceci) il sagit des GtkBox Il sagit de la meacutethode que jutilise le plus souvent Ce nestpeut-ecirctre pas la plus simple agrave maicirctriser mais elle extrecircmement souple et puissante Elle consiste agrave creacuteer une boicirctepuis agrave y ajouter les widgets les uns apregraves les autres (soit au deacutebut soit agrave la fin) Il existe deux classes heacuteritant deGtkBox les GtkVBox qui empilent les widgets dans le sens vertical et les GtkHBox qui font de mecircme mais dansle sens horizontal Les fonctions pour manipuler ces deux classes sont les mecircmes seule la fonction pour les creacuteerportent un nom diffeacuterent

GtkWidget gtk_vbox_new (gboolean homogeneous gint spacing)GtkWidget gtk_hbox_new (gboolean homogeneous gint spacing)

Le paramegravetre homogeneous permet de reacuteserver pour chaque widget une zone de taille identique (zone que le widgetnest pas obligeacute de remplir) et spacing permet dajouter une bordure en pixels (espacement autour de la GtkBox)Ensuite il suffit dajouter les diffeacuterents widgets gracircce aux fonctions

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)

Qui ajoutent reacuteciproquement le widget child au deacutebut et agrave la fin de box Le paramegravetre expand permet au widget davoirle plus de place possible (si le paramegravetre homogeneous vaut TRUE cette option a aucun effet) Si plusieurs widgetont ce paramegravetre agrave TRUE ils se partagent de faccedilon eacutegale lespace Loption fill permet au widget de remplir toutlespace qui lui ait reacuteserveacute

Pour reacuteellement comprendre linfluence de ces paramegravetres il faut faire des tests en modifiant un agrave un chaqueparamegravetre et observer les effets dun redimentionnement de la fenecirctre principale

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 14 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Le plus gecircnant avec cette meacutethode cest quil faut jongler entre les GtkHBox et les GtkVBox en les imbriquant pourobtenir le reacutesultat souhaiter nheacutesitez pas agrave utiliser une feuille et un crayon )

Pour en revenir agrave notre eacutediteur de texte nous allons preacuteparer notre application agrave contenir les futurs widgetsNous utilisons un GtkVBox pour lensemble des widgets (il sagit de la boicircte principale qui pourra contenir dautresGtkContainer selon nos besoins)

maincinclude ltstdlibhgtinclude ltgtkgtkhgtinclude callbackh

int main (int argc char argv) GtkWidget p_window = NULL GtkWidget p_main_box = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (cb_quit) NULL)

Creation du conteneur principal p_main_box = gtk_vbox_new (FALSE 0) gtk_container_add (GTK_CONTAINER (p_window) p_main_box)

Creation du bouton Quitter GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_QUIT) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_quit) NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_button FALSE FALSE 0)

Affichage de la fenetre principale gtk_widget_show_all (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

IV-D - Code source

chapitre4zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 15 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

V - Afficher le contenue dun fichier

V-A - Aperccedilu

Cliquez pour agrandir

V-B - Saisir du texte

Les choses seacuterieuses vont commencer il sagit de mettre en place le widget qui va nous permettre dafficher etdeacutediter du texte Il sagit de la classe GtkTextView Gracircce agrave GTK+ la mise en place est toujours aussi simple

mainc GtkWidget p_text_view = NULL Creation de la zone de texte p_text_view = gtk_text_view_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_text_view TRUE TRUE 0)

Comme il sagit de la partie centrale de notre application nous demandons agrave ce quelle prenne le plus de placepossible (gracircce agrave la fonction gtk_box_pack_start)

Puisque nous voulons afficher les boutons en dessous de la zone de texte il faut ajouter ce morceau de code avantcelui creacuteant le bouton

V-C - Ouvrir un fichier

Maintenant nous avons une belle zone de texte il faut la remplir avec le contenu dun fichier Pour ce faire nousallons commencer par ajouter un bouton ouvrir

mainc Creation du bouton Ouvrir GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_OPEN) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_open) p_text_view) gtk_box_pack_start (GTK_BOX (p_main_box) p_button FALSE FALSE 0)

Si vous exeacutecutez le programme maintenant (3) vous remarquerez que les boutons sont ajouteacutes les uns en dessousdes autres ce qui diminue la zone de saisie (avec deux boutons ce nest pas gecircnant mais au bout dune dizaineccedila risque decirctre probleacutematique) Pour pallier ce problegraveme nous allons utiliser un nouveau style de GtkBox lesGtkButtonBox qui sont preacutevus pour contenir des boutons (ccedila tombe plutocirct bien D) Donc pour eacuteviter de diminuerla zone de saisie et comme nous avons de la place en largueur nous allons utiliser un GtkHButtonBox qui va ecirctreinclus dans la p_main_box Voici les modifications agrave effectuer

mainc GtkWidget p_button_box = NULL Creation du conteneur pour les boutons p_button_box = gtk_hbutton_box_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_button_box FALSE FALSE 0)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 16 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc gtk_box_pack_start (GTK_BOX (p_button_box) p_button FALSE FALSE 0) gtk_box_pack_start (GTK_BOX (p_button_box) p_button FALSE FALSE 0)

Maintenant il nous reste plus quagrave creacuteer la fonction cb_open dans le fichier callbackc pour linstant nous nouscontenterons douvrir toujours le mecircme fichier nous verrons plus tard comment laisser le choix agrave lutilisateur

callbackcdefine DEFAULT_FILE mainc

void cb_open (GtkWidget p_widget gpointer user_data) open_file (DEFAULT_FILE GTK_TEXT_VIEW (user_data))

Parametre inutilise (void)p_widget

Vous aurez compris que lon va deacuteleacuteguer tout le travail agrave la fonction open_file qui devra ouvrir le fichier dont le nomest passeacute en premier paramegravetre pour lafficher dans le GktTextView

Jai fait ce choix pour deux raisons le code dune fonction callback peut ecirctre tregraves conseacutequent (surtout si lon souhaitequelle affiche une boicircte de dialogue) et aussi parce que cb_open nest peut ecirctre pas la seule fonction agrave copierun fichier dans un GtkTextView (par exemple lors de la creacuteation dun nouveau fichier lon peut vouloir copier unsquelette de fichier)

Pour copier notre fichier plutocirct que dutiliser la fonction fgets nous allons nous servir de la glib (4) qui proposela fonction

gboolean g_file_get_contents (const gchar filename gchar contents gsize length GError error)

Qui nous renvoit le contenu du fichier nommeacute filename dans le tampon contents Il est possible de reacutecupeacuterer lenombre de caractegraveres copieacutes et retourne TRUE en cas de succegraves sinon FALSE et dans ce cas une structure de typeGError est creacutee pour en savoir plus sur le type derreur rencontreacute

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView else print_warning (Impossible douvrir le fichier sn file_name)

Je pense quun certain nombre dexplications simpose (surtout si je vais trop vite nheacutesitez pas agrave marrecircter )

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 17 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

bull g_return_if_fail est une macro qui peut ecirctre compareacutee agrave assert sauf quelle se contente de sortir de la fonctionsi lexpression passeacutee en paramegravetre est fausse Cest une meacutethode pratique pour veacuterifier la validiteacute desparamegravetres (si la fonction doit retourne une valeur utiliseacute plutocirct g_return_val_if_fail qui prend un secondparamegravetre la valeur agrave retourner)

bull Ensuite on essaie de reacutecupeacuterer le contenu de notre fichier

bull Si cela eacutechoue nous le signalons agrave lutilisateur agrave laide de la fonction print_warning

bull Le type gchar est une redeacutefinition du type char par la glib (il en va de mecircme pour tous les autres types du C)privileacutegiez ces types lorsque vous utilisez des fonctions de cette bibliothegraveques

Mais quest-ce donc cette fonction print_warning Cest une fonction que nous allons creacuteer semblable agrave printf quisignalera agrave lutilisateur quune erreur non critique est survenue Comme nous navons pas encore abordeacute les boicirctesde dialogue pour afficher un message il sagira pour linstant dune simple redeacutefinition de printf Pendant que noussommes dans laffichage des messages nous allons aussi creacuteer deux fonctions print_info et print_error qui vontrespectivement afficher un message dinformation et un message derreur critique (ce qui entraicircne la terminaison duprogramme) tout ceci dans un nouveau fichier errorc

errorhifndef H_ERRORdefine H_ERROR

void print_info (char )void print_warning (char )void print_error (char )

endif not H_ERROR

errorcinclude ltstdarghgtinclude ltstdiohgtinclude ltstdlibhgtinclude errorh

void print_info (char format ) va_list va

va_start (va format) printf (Information ) vprintf (format va) printf (n)

void print_warning (char format ) va_list va

va_start (va format) fprintf (stderr Erreur ) vfprintf (stderr format va) fprintf (stderr n)

void print_error (char format ) va_list va

va_start (va format) fprintf (stderr Erreur fatale ) vfprintf (stderr format va) fprintf (stderr n) exit (EXIT_FAILURE)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 18 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

Pour en finir avec louverture dun fichier il nous reste agrave copier contents dans le GtkTextView En fait le GtkTextViewne gegravere que la forme pour modifier le contenu il faut passer par les GtkTextBuffer Commenccedilons donc par reacutecupeacutererce fameux GtkTextBuffer

callbackc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (p_text_view)

Et pour finir on utilise la fonction

void gtk_text_buffer_insert (GtkTextBuffer buffer GtkTextIter iter const gchar text gint len)

Reacutecapitulons buffer est le GtkTextBuffer que lon vient de reacutecupeacuterer text cest le texte agrave afficher et len la taille dece dernier (ou -1 sil sagit dune chaicircne de caractegraveres au sens du langage C)

Mais quest-ce donc ce GtkTextIter On peut voir cela comme un curseur virtuel qui indique la position agrave laquelleeffectuer linsertion de texte dans le GtkTextBuffer (5) Allons voir ce que la documentation peut nous apprendreagrave leur sujet (6)

typedef struct GtkTextIter is an opaque datatype ignore all these fields Initialize the iter with gtk_text_buffer_get_iter_ functions GtkTextIter

Voilagrave on a notre solution suffit de rechercher les fonctions commenccedilant par gtk_text_buffer_get_iter_ voici la liste

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)

La fonction gtk_text_buffer_get_iter_at_line fait parfaitement laffaire

callbackc GtkTextIter iter

gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1)

Cependant si vous ne voulez pas avoir de problegravemes avec le codage des caractegraveres il vaut mieux convertir le codagelocal vers utf8 Voici le reacutesultat final

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 19 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gchar utf8 = NULL GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_text_buffer_insert (p_text_buffer ampiter utf8 -1) g_free (utf8) utf8 = NULL

V-D - La petite touche finale

Pour finir cette laborieuse partie sur une petite touche estheacutetique nous allons demander agrave GTK+ de nous lancerlapplication en plein eacutecran Pour se faire il suffit dajouter lors de la creacuteation de la fenecirctre principale

maincgtk_window_maximize (GTK_WINDOW (p_window))

On peut mecircme se permettre une pointe dexcentriciteacute en modifiant le titre de notre fenecirctre

maincgtk_window_set_title (GTK_WINDOW (p_window) Editeur de texte en GTK+)

V-E - Code source

chapitre5zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 20 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VI - Choisir un fichier

VI-A - Aperccedilu

Cliquez pour agrandir

VI-B - Utilisation dun GtkFileChooserFile

Jusquagrave preacutesent lutilisateur navait pas le choix quant au fichier agrave ouvrir heureusement GTK+ vient agrave notre aide gracircceau widget GtkFileChooserFile qui est tout simplement une boicircte de dialogue qui propose agrave lutilisateur de seacutelectionnerun fichier dans son arborescence disque

Commenccedilons par creacuteer notre boicircte de dialogue dans la fonction cb_open

callbackcvoid cb_open (GtkWidget p_widget gpointer user_data) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Ouvrir un fichier NULL GTK_FILE_CHOOSER_ACTION_OPEN GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_OPEN GTK_RESPONSE_ACCEPT NULL)

Cette fonction neacutecessite le titre de la boicircte de dialogue une fenecirctre parente le type daction (ici on souhaite ouvrir unfichier GTK+ autorisera lutilisateur agrave seacutelectionner uniquement les fichiers existants) Pour finir il sagit dun couple devaleurs GTK_STOCK_ITEMGTK_STOCK_RESPONSE qui permet de creacuteer un bouton utilisant le stock ID speacutecifieacuteet lorsque celui-ci est cliqueacute la fonction servant agrave lancer la boicircte de dialogue retournera le reacuteponse ID correspondantIl existe une seacuterie de valeurs deacutefinies par GTK+ quil est conseilleacute dutiliser

typedef enum GTK returns this if a response widget has no response_id or if the dialog gets programmatically hidden or destroyed GTK_RESPONSE_NONE = -1

GTK wont return these unless you pass them in as the response for an action widget They are for your convenience GTK_RESPONSE_REJECT = -2 GTK_RESPONSE_ACCEPT = -3

If the dialog is deleted GTK_RESPONSE_DELETE_EVENT = -4

These are returned from GTK dialogs and you can also use them yourself if you like GTK_RESPONSE_OK = -5 GTK_RESPONSE_CANCEL = -6 GTK_RESPONSE_CLOSE = -7 GTK_RESPONSE_YES = -8

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 21 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GTK_RESPONSE_NO = -9 GTK_RESPONSE_APPLY = -10 GTK_RESPONSE_HELP = -11 GtkResponseType

Nous indiquons la fin des couples stock idreacuteponse id avec la valeur NULL

Une fois la boicircte de dialogue creacuteee on demande agrave GTK+ de lafficher gracircce agrave la fonction gtk_dialog_run puis onreacutecupegravere sa valeur de retour qui correspond au bouton cliqueacute par lutilisateur

callbackc if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

Ici ce qui nous inteacuteresse cest lorsque que lutilisateur clique sur le bouton ouvrir (donc gtk_dialog_run renvoieGTK_RESPONSE_ACCEPT) dans ce cas il nous suffit de reacutecupeacuterer le nom du fichier seacutelectionneacute puis de louvrir

callbackc gchar file_name = NULL

file_name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) open_file (file_name GTK_TEXT_VIEW (user_data)) g_free (file_name) file_name = NULL

Pour finir dans tous les cas on noublie pas de deacutetruire la boicircte de dialogue

callbackc gtk_widget_destroy (p_dialog)

Et voilagrave le travail lutilisateur peut ouvrir le fichier quil souhaite

VI-C - Code source

chapitre6zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 22 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VII - Interlude

Avant daller plus loin dans lameacutelioration de linterface de notre eacutediteur il est neacutecessaire de modifier sonfonctionnement interne (ne vous inquieacutetez je nai pas dit chambouler) en effet souvenez-vous dans lintroduction jaieacutevoqueacute la possibiliteacutes douvrir plusieurs documents gracircce agrave un systegraveme donglets Pour cela il faut sauvegarder lesproprieacuteteacutes de chaque document ouvert Pris agrave temps ce genre de modification nest pas trop lourde mais si nousattendons cela risque de devenir un vrai casse tecircte

Pour cela nous allons utiliser une structure de donneacutee pour chaque document ouvert qui devra garder en meacutemoirele chemin complet du fichier (ou NULL si le document nest pas encore sauvegarder) sil agrave eacutetait modifier depuis laderniegravere sauvegarde et le GtkTextView qui sert agrave son affichage Voici donc la structure qui va nous servir

documenthtypedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

Sachant que nous serons ameneacute agrave stocker plusieurs occurrences de cette structure il serait bon de reacutefleacutechir degravesmaintenant agrave la structure de donneacutee agrave utiliser pour les stocker La premiegravere ideacutee qui vient agrave lesprit est un tableaualloueacute dynamiquement cependant lutilisateur peut souhaiter fermer un document qui se trouve au milieu on estalors obligeacute de deacutecaler toutes les cellules en amont Dans ce cas il parait naturel dutiliser une liste chaicircneacutee Parchance la glib propose une bibliothegraveque de gestion des listes chaicircneacutees cela nous fera gagner du temps le momentvenu Pour linstant on se contente de creacuteer une structure de donneacutees qui contiendra tous les documents ouverts(stockeacutee dans une GList) et un pointeur sur le document actif (actuellement comme nous navons quun documentouvert en mecircme temps on manipulera uniquement ce pointeur)

documenthtypedef struct GList tous document_t actif docs_t

Maintenant se pose le problegraveme de savoir comment transmettre cette structure On pourrait se servir du paramegravetreuser_data preacutesent dans toutes les fonctions callback mais certaines fonctions utilise deacutejagrave ce paramegravetre (la fonctioncb_open par exemple) il faudrait creacuteer un champs suppleacutementaire dans notre structure documents_s Une solutionplus simple est de creacuteer une variable globale agrave lensemble du programme Ceux qui passe reacuteguliegraverement sur le forumC savent que cest fortement deacuteconseilleacute mais ici nous nous trouvons dans lune des rares exceptions agrave la regravegle Detoute faccedilon cela revient au mecircme que de passer ladresse de notre structure agrave toutes les fonctions callback Nousdeacutefinissons donc un nouveau fichier den-tecircte

documenthifndef H_DOCUMENTdefine H_DOCUMENT

include ltgtkgtkhgt

typedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 23 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

documenthtypedef struct GList tous document_t actif docs_t

extern docs_t docs

endif not H_DOCUMENT

Et dans le fichier mainc

maincinclude documenth

docs_t docs = NULL NULL

Pour linstant la seule fonction qui modifie leacutetat dun document est la fonction open_file il faut donc inclure documenthdans callbackc et modifier leacutegegraverement la fonction pour enregistrer le document ouvert

callbackc if (g_file_get_contents (file_name ampcontents NULL NULL)) Pour linstant il faut allouer la memoire par la suite on modifira simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = g_strdup (file_name) Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = p_text_view Le document vient detre ouvert il nest donc pas modifie docsactif-gtsauve = TRUE

Ne soyez pas choqueacute si je ne teste pas le retour de la fonction g_malloc pour veacuterifier quilnest pas NULL En effet cette derniegravere met fin agrave lapplication si lallocation eacutechoue

VII-A - Code source

chapitre7zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 24 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VIII - Sauvegarder les modification

VIII-A - Aperccedilu

Cliquez pour agrandir

VIII-B - Enregistrer

Avant de pouvoir sauvegarder un document il faut quil soit modifieacute Comment savoir que le contenu du fichier a eacuteteacutemodifier Gracircce au signal changed du GtkTextBuffer que nous interceptons gracircce agrave la fonction cb_modifie

mainc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (p_text_view)) g_signal_connect (G_OBJECT (p_text_buffer) changed G_CALLBACK (cb_modifie) NULL)

Cette derniegravere modifie simplement le champ sauve du document

callbackcvoid cb_modifie (GtkWidget p_widget gpointer user_data) if (docsactif) docsactif-gtsauve = FALSE

Pour la sauvegarde il faut distinguer deux cas soit il sagit de la premiegravere sauvegarde du fichier il faut alors demanderle nom du fichier agrave lutilisateur (cela ressemble fortement agrave louverture dun fichier) soit le fichier est deacutejagrave preacutesent surle disque il suffit de remplacer son contenu par celui du GtkTextViewer Nous avons convenu quun fichier qui neacutetaitpas encore enregistreacute avait sa proprieacuteteacute chemin agrave NULL

Bien sucircr cela na lieu que si un fichier est ouvert et quil a eacuteteacute modifieacute depuis sa derniegravere sauvegarde

callbackcvoid cb_save (GtkWidget p_widget gpointer user_data) if (docsactif) if (docsactif-gtsauve) Le fichier na pas encore ete enregistre if (docsactif-gtchemin) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Sauvegarder le fichier NULL GTK_FILE_CHOOSER_ACTION_SAVE GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_SAVE GTK_RESPONSE_ACCEPT NULL) if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 25 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc docsactif-gtchemin = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) gtk_widget_destroy (p_dialog) Soit le fichier a deja ete enregistre soit lutilisateur vient de nous fournir son nouvel enplacement on peut donc lenregistrer if (docsactif-gtchemin) else print_warning (Aucun document ouvert)

Il nous reste plus quagrave reacutecupeacuterer le contenu du GtkTextViewer et le copier dans le fichier chemin sans oublier dereconvertir le texte dans le codage local

callbackc FILE fichier = NULL

fichier = fopen (docsactif-gtchemin w) if (fichier) gchar contents = NULL gchar locale = NULL GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) contents = gtk_text_buffer_get_text (p_text_buffer ampstart ampend FALSE) locale = g_locale_from_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL fprintf (fichier s locale) g_free (locale) locale = NULL fclose (fichier) fichier = NULL docsactif-gtsauve = TRUE else print_warning (Impossible de sauvegarder le fichier s docsactif-gtchemin)

Le dernier paramegravetre de la fonction gtk_text_buffer_get_text est mis agrave FALSE car nous ne voulons pas enregistrerles caractegraveres invisibles preacutesent dans le GtkTextBuffer Ces caractegraveres servent agrave mettre en forme le texte (taillecouleur) nous pourrions creacuteer un nouveau format de fichier pour enregistrer la mise en forme

VIII-C - Enregistrer sous

Pour enregistrer notre document sous un autre nom il suffit de faire croire agrave cb_save que le document na pas encoreeacutetait enregistreacute tout simplement en changeant chemin agrave NULL et sauve agrave FALSE

callbackcvoid cb_saveas (GtkWidget p_widget gpointer user_data)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 26 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (docsactif) document_t tmp = docsactif

docsactif-gtchemin = NULL docsactif-gtsauve = FALSE cb_save (p_widget user_data) if (docsactif-gtsauve) (docsactif) = tmp else print_warning (Aucun document ouvert)

Il ne faut pas oublier que lutilisateur peut annuler lenregistrement de ce fait nous sauvegardons leacutetat du documentet si la sauvegarde na pas eu lieu on le restaure

VIII-D - Code source

chapitre8zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 27 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IX - Creacuteer un nouveau document

IX-A - Aperccedilu

Cliquez pour agrandir

IX-B - Nouveau fichier

Maintenant que lutilisateur peut ouvrir et fermer un fichier il est inteacuteressant de lui donner la possibiliteacute den creacuteerun nouveau Je ne reviens pas sur la creacuteation du bouton (ccedila devrait deacutejagrave ecirctre fait D) passons directement agrave lafonction cb_new

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) Pour linstant il faut allouer la memoire par la suite on modifiera simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = NULL Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = GTK_TEXT_VIEW (user_data) Le document vient detre creer il nest donc pas modifie docsactif-gtsauve = TRUE gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Je ne sais pas vous mais pour ma part jai fait un copiercoller de la fonction open_file Et oui ouvrir un document peutse reacutesumer agrave creacuteer un document vide puis remplir le GtkTextView avec le fichier souhaiteacute On peut donc simplifiernotre fonction open_file ainsi

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

cb_new (NULL p_text_view) gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE) p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1) Nous sommes obliges de remetre sauve a TRUE car linsertion du contenu du fichier dans le GtkTextView a appele cb_modfie docsactif-gtsauve = TRUE else print_warning (Impossible douvrir le fichier sn file_name)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 28 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc

Cest beau la factorisation du code Par contre nous sommes obligeacutes de remettre sauve agrave TRUE car nous avonsmodifieacute le GtkTextBuffer

IX-C - Code source

chapitre9zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 29 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

X - Fermer

X-A - Aperccedilu

Cliquez pour agrandir

X-B - Fermer un fichier

Maintenant que nous allouons de la meacutemoire il faut la libeacuterer agrave un endroit Logiquement cela va ecirctre fait agrave la fermeturedu document en guise dexercice je vous laisse creacuteer le bouton dans notre boicircte agrave bouton

Allez je vous aide le stock id correspondant est GTK_STOCK_CLOSE

Voilagrave maintenant si tout cest bien passeacute vous devriez ecirctre arriveacute dans le fichier callbackc avec quelque choseressemblant agrave

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data)

Lorsque lon ferme un document il faut vider le GtkTextView (avec les onglets on se contentera de le supprimer)pour cela il faut reacutecupeacuterer le deacutebut et la fin du GtkTextBuffer et demander agrave GTK+ de supprimer tout ce qui ce trouveentre les deux iteacuterateurs

callbackc Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) gtk_text_buffer_delete (p_text_buffer ampstart ampend) else print_warning (Aucun document ouvert)

Bien sucircr il ne faut pas oublier de libeacuterer la meacutemoire

callbackc g_free (docsactif-gtchemin) docsactif-gtchemin = NULL docsactif-gtp_text_view = NULL g_free (docsactif) docsactif = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 30 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour symboliser la fermeture dun document nous deacutesactivons le GtkTextView lors de la fermeture (ne pas oublierde le faire aussi dans mainc)

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) FALSE)

Et nous le reacuteactivons lors de louverture si celle si reacuteussie

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Lorsque lutilisateur quitte lapplication il faut bien sucircr fermer le document sil y en a un ouvert

void cb_quit (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data) gtk_main_quit()

Et aussi lorsquil creacuteeacute un nouveau document (et par conseacutequent lorsquil ouvre un fichier puisque lon fait appel agravecb_new)

void cb_new (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data)

X-C - Enregistrer avant de fermer

Si le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde geacuteneacuteralement le programme le signale agrave lutilisateur etlui propose de sauvegarder ou dannuler la fermeture Pour se faire nous devons modifier la fonction cb_close avantde fermer le document nous allons afficher une boicircte de dialogue

Pour creacuteer une boicircte de dialogue simplement il existe la classe GtkDialog et comme nous avons besoin de boutons(pour que lutilisateur fasse son choix) nous allons creacuteer notre boicircte avec la fonction

GtkWidget gtk_dialog_new_with_buttons (const gchar title GtkWindow parent GtkDialogFlags flags const gchar first_button_text )

Nous retrouvons les mecircmes options que pour le GtkFileChooserDialog mis agrave part option du type GtkDialogFlags

typedef enum GTK_DIALOG_MODAL = 1 ltlt 0 appel gtk_window_set_modal (win TRUE) GTK_DIALOG_DESTROY_WITH_PARENT = 1 ltlt 1 appel gtk_window_set_destroy_with_parent () GTK_DIALOG_NO_SEPARATOR = 1 ltlt 2 Pas de barre de separation au dessus des boutons GtkDialogFlags

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 31 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Nous nous contenterons de rendre notre fenecirctre modale (7)

Pour avoir accegraves agrave notre fenecirctre principale nous ajoutons un champs p_main_window agrave notre structure globaledocs_t que nous initialisons dans la fonction main

mainc docsp_main_window = GTK_WINDOW (p_window)

Il nous reste plus qua creacuteer notre boicircte de dialogue avec trois boutons Oui Non Annuler

callbackc if (docsactif-gtsauve) GtkWidget p_dialog = NULL

p_dialog = gtk_dialog_new_with_buttons (Sauvegarder docsp_main_window GTK_DIALOG_MODAL GTK_STOCK_YES GTK_RESPONSE_YES GTK_STOCK_NO GTK_RESPONSE_NO GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL NULL)

Nous obtenons donc une structure de type GtkDialog

typedef struct GtkWidget vbox GtkWidget action_area GtkDialog

Nous remarquons que cette structure contient deux membres qui permettent dacceacuteder agrave une GtkBox ougrave nous allonsajouter le contenu de la fenecirctre et agrave la partie contenant les boutons

Ensuite la construction de la fenecirctre est identique agrave celle de la fenecirctre principale ici nous nous contenterons dajouterun GtkLabel

callbackc GtkWidget p_label = NULL p_label = gtk_label_new (Voulez-vous sauvegarder les modifications ) gtk_box_pack_start (GTK_BOX (GTK_DIALOG (p_dialog)-gtvbox) p_label TRUE TRUE 0)

Une fois notre fenecirctre precircte il suffit de faire appel agrave la fonction gtk_dialog_run qui va afficher notre GtkDialog et nousretourner le reacuteponse id correspondant au bouton cliqueacute par lutilisateur

callbackc switch (gtk_dialog_run (GTK_DIALOG (p_dialog))) case GTK_RESPONSE_YES cb_save (p_widget user_data) break case GTK_RESPONSE_NO break case GTK_RESPONSE_CANCEL gtk_widget_destroy (p_dialog) return break

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 32 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc gtk_widget_destroy (p_dialog)

Si lutilisateur clique sur non on ne fait rien (le document sera simplement fermeacute) sur oui on enregistre avant defermer et pour finir sil annule on quitte la fonction

X-D - Code source

chapitre10zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 33 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XI - Les barres de deacutefilement

XI-A - Aperccedilu

Cliquez pour agrandir

XI-B - Ajouter des barres de deacutefilement

Apregraves le dernier chapitre quelque peu laborieux voici une partie plus simple mais qui va rendre notre applicationplus pratique En effet si vous avez essayeacute douvrir un fichier de grande taille vous avez pu remarquer que pourpouvoir lire la fin du fichier il fallait utiliser les touches du clavier pas tregraves convivial

Pour rendre la navigation plus aiseacutee on utilise des barres de deacutefilement

mainc GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_scrolled_window TRUE TRUE 0)

Creation de la zone de texte gtk_container_add (GTK_CONTAINER (p_scrolled_window) p_text_view)

Le constructeur de notre GtkScrolledWindow prend en argument deux GtkAdjustment qui permettent de deacutefinirdiffeacuterentes proprieacuteteacutes de la barre de deacutefilement (taille dune page la position de deacutepart) nous laissons GTK+ faireen passant NULL

Cest un bon deacutebut mais estheacutetiquement on peut faire mieux mecircme sil nest pas utile davoir une barre de deacutefilementelle est quand mecircme afficheacutee On peut demander agrave GTK+ de les afficher que si cela est neacutecessaire

mainc gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC)

En fait nous avons de la chance car la classe GtkTextView fait partie des widget qui supporte de faccedilon native les barresde deacutefilement Comment le savoir Ce genre de widget possegravede une ou deux proprieacuteteacutes de type GtkAdjustment (unepour la barre verticale lautre pour la barre horizontale) Actuellement seulement trois classes en sont capables lesGtkTextView les GtkTreeView et les GtkLayout

Comment faire pour les autres widgets Il faut passer par une classe adaptateur GtkViewport afin de creacuteer lesGtkAdjustment

XI-C - Code source

chapitre11zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 34 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XII - Les menus

XII-A - Aperccedilu

Cliquez pour agrandir

XII-B - Creacuteation du menu

Pour simplifier nous avons utiliseacute des boutons pour permettre agrave lutilisateur de creacuteer un document ouvrir un fichierMais il est plus courant dutiliser un menu pour afficher ces options GTK+ propose trois maniegraveres de creacuteer un menu

bull GtkItemFactory cette meacutethode est obsolegravete depuis la version 24 de GTK+

bull GtkUIManager cest ce quon appel une usine agrave gaz pour en savoir plus vous pouvez vous reporter aututoriel Utilisation de GtkUIManager

bull GtkMenu cest ce widget que nous allons eacutetudier il permet de creacuteer un menu manuellement (agrave lopposeacute deGtkUIManager)

Un menu selon GTK+ est composeacute de plusieurs eacuteleacutements

bull GtkMenuBar la barre de menu elle-mecircme

bull GtkMenu la partie deacuteroulante qui contient les diffeacuterents eacuteleacutements

bull GtkMenuItem cest sur ce widget que lutilisateur clique pour lancer une action

Pour commencer faisons linventaire de ce que nous avons besoin

bull Un GtkMenuBar qui sert de base au menu

bull Un GtkMenu pour commencer nous nous aurons dun menu Fichier

bull Six GtkMenuItem pour remplacer nos six boutons

Commenccedilons par la creacuteation du menu nous mettons ce code dans un nouveau fichier dont seul la fonction menu_newsera accessible

menucGtkMenuBar menu_new (gpointer user_data) GtkWidget p_menu_bar = NULL

p_menu_bar = gtk_menu_bar_new () return GTK_MENU_BAR (p_menu_bar)

Le paramegravetre user_data nous servira lors de la connexion des callbacks (nous en avons besoin pour les fonctionscb_new et cb_open)

Ensuite nous allons creacuteer notre sous menu Fichier

menuc Menu Fichier

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 35 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

menuc GtkWidget p_menu = NULL GtkWidget p_menu_item = NULL

p_menu = gtk_menu_new () p_menu_item = gtk_menu_item_new_with_mnemonic (_Fichier) gtk_menu_item_set_submenu (GTK_MENU_ITEM (p_menu_item) p_menu) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu_bar) p_menu_item) return GTK_MENU_BAR (p_menu_bar)

Un sous menu est en fait un GtkMenuItem auquel on assigne un GtkMenu Il faut bien sucircr terminer la creacuteation dusous-menu en lajoutant agrave la barre de menu

Pour finir nous creacuteons les eacuteleacutements du menu les GtkItemMenu Il existe plusieurs types deacuteleacutements (comparableaux diffeacuterents types de bouton) pour commencer nous nutiliserons que le type de base Comme cette opeacuteration estreacutepeacutetitive nous allons creacuteer une fonction pour le faire

menucstatic void menu_item_new (GtkMenu p_menu const gchar title GCallback callback gpointer user_data) GtkWidget p_menu_item = NULL

p_menu_item = gtk_menu_item_new_with_mnemonic (title) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu) p_menu_item) g_signal_connect (G_OBJECT (p_menu_item) activate callback user_data)

Pour permettre agrave lutilisateur dacceacuteder aux diffeacuterents eacuteleacutements du menu agrave laide de la touche ltAltgt nous utilisonsdes mneacutemoniques par exemple pour quitter leacutediteur il suffit de faite Alt+F puis Q Et voici le code pour creacuteer nossix eacuteleacutements du menu

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau G_CALLBACK (cb_new) user_data) menu_item_new (GTK_MENU (p_menu) _Ouvrir G_CALLBACK (cb_open) user_data) menu_item_new (GTK_MENU (p_menu) _Enregistrer G_CALLBACK (cb_save) user_data) menu_item_new (GTK_MENU (p_menu) Enregistrer _sous G_CALLBACK (cb_saveas) user_data) menu_item_new (GTK_MENU (p_menu) _Fermer G_CALLBACK (cb_close) user_data) menu_item_new (GTK_MENU (p_menu) _Quitter G_CALLBACK (cb_quit) user_data)

Voilagrave notre menu est creacuteeacute il nous reste plus quagrave linteacutegrer agrave notre fenecirctre

mainc gtk_box_pack_start (GTK_BOX (p_main_box) GTK_WIDGET (menu_new (p_text_view)) FALSE FALSE 0)

Le problegraveme cest que nous avons besoin de passer le GtkTextView lors de la creacuteation du menu (qui est utiliseacute par lesfonctions cb_new et cb_open) or celui-ci est creacuteeacute apregraves le menu (puisque nous creacuteons les widgets dans lordre ougrave ilfaut les inteacutegrer agrave linterface (8) ) nous devons creacuteer le GtkTextView (seul lappel agrave gtk_text_view_new est deacuteplaceacute)

XII-C - Code source

chapitre12zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 36 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIII - Les barres doutils

XIII-A - Aperccedilu

Cliquez pour agrandir

XIII-B - Creacuteation dune barre doutils

La creacuteation dune barre doutils ressemble fort agrave celle dun menu en plus simple puisquil ny a pas de sous menu on creacutee notre barre doutils (gtk_toolbar_new) puis les eacuteleacutements de la barre pour cela on utilise des boutons(gtk_tool_button_new_from_stock) que lon inseacutere dans la barre (gtk_toolbar_insert) Pas conseacutequent notre fichierbarreoutilsc ressemble agrave menuc

barreoutilscinclude ltgtkgtkhgtinclude callbackhinclude barreoutilsh

static void toolbar_item_new (GtkToolbar const gchar GCallback gpointer)

GtkToolbar toolbar_new (gpointer user_data) GtkWidget p_toolbar = NULL

p_toolbar = gtk_toolbar_new () toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_NEW G_CALLBACK (cb_new) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_OPEN G_CALLBACK (cb_open) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE G_CALLBACK (cb_save) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE_AS G_CALLBACK (cb_saveas) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_CLOSE G_CALLBACK (cb_close) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_QUIT G_CALLBACK (cb_quit) user_data) return GTK_TOOLBAR (p_toolbar)

static void toolbar_item_new (GtkToolbar p_toolbar const gchar stock_id GCallback callback gpointer user_data) GtkToolItem p_tool_item = NULL

p_tool_item = gtk_tool_button_new_from_stock (stock_id) g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data) gtk_toolbar_insert (p_toolbar p_tool_item -1)

Le code nest pas complet car lorsque jexeacutecute le programme GTK+ affiche en plus des icocircnes le texte sous lesboutons Pour modifier cela il suffit dajouter une ligne de code

barreoutilsc gtk_toolbar_set_style (GTK_TOOLBAR (p_toolbar) GTK_TOOLBAR_ICONS)

Pourquoi gtk_tool_button_new_from_stock retourne un GtkToolItem et non un GtkWidgetcomme nous avons eacuteteacute habitueacute jusquagrave preacutesent Il sagit dune bizarrerie de GTK+ dontje ne connais pas la raison

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 37 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour anticiper un changement dinterface (dans GTK+ 30 peut ecirctre ) nous aurions pueacutecrire

Gtkwidget p_tool_item = NULL

p_tool_item = GTK_WIDGET (gtk_tool_button_new_from_stock (stock_id))g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data)gtk_toolbar_insert (p_toolbar GTK_TOOL_ITEM (p_tool_item) -1)

XIII-C - Code source

chapitre13zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 38 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIV - Les racourcis clavier

XIV-A - Aperccedilu

Cliquez pour agrandir

XIV-B - Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mneacutemoniques ces derniers permettent dacceacuteder agrave un eacuteleacutementseacutequentiellement alors que les raccourcis appellent une fonction si lutilisateur appuie simultaneacutement sur une ouplusieurs touches (geacuteneacuteralement de la forme ltModificateurgtTouche ougrave Modificateur repreacutesente les touches ShiftAlt et Control) Ce raccourci peut ecirctre attacheacute agrave un eacuteleacutement du menu mais ceci nest pas obligatoire

Les raccourcis sont regroupeacutes en groupe dans un GtkAccelGroup quil faut commencer par creacuteer

raccourciscinclude ltgtkgtkhgtinclude callbackhinclude raccourcish

GtkAccelGroup accel_group_new (gpointer user_data) GtkAccelGroup p_accel_group = NULL

p_accel_group = gtk_accel_group_new () return p_accel_group

Vous commencez agrave avoir lhabitude de cette organisation nous allons donc creacuteer une fonction qui va se chargerdajouter un raccourci au groupe

raccourciscstatic void accelerator_new (GtkAccelGroup p_accel_group const gchar accelerator const gchar accel_path GCallback callback gpointer user_data) guint key GdkModifierType mods GClosure closure = NULL

gtk_accelerator_parse (accelerator ampkey ampmods) closure = g_cclosure_new (callback user_data NULL) gtk_accel_group_connect (p_accel_group key mods GTK_ACCEL_VISIBLE closure) gtk_accel_map_add_entry (accel_path key mods)

La fonction gtk_accelerator_parse permet de deacutecomposer une chaicircne de caractegraveres de la forme ltControlgtF1 ouencore ltAltgtA en numeacutero de touche et modificateur

En plus des touches pour creacuteer un raccourci clavier nous avons besoin dune fonction agrave appeler lorsque lutilisateurappuie sur les touches speacutecifieacutees gtk_accel_group_connect attend une fonction du type GClosure regardons ladocumentation de gobject pour savoir agrave quoi cela correspond

typedef struct

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 12 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

maincgtk_container_add (GTK_CONTAINER (p_window) p_button)

Ce meacutecanisme de transtypage permet agrave GTK+ de veacuterifier que notre GtkWidget est bien compatible avec lutilisationque lon souhaite en faire En cas deacutechec GTK+ nous preacutevient en affichant un message dans la console

(gtk_boutonexe1044) Gtk-CRITICAL gtk_container_add assertion `GTK_IS_CONTAINER (container) failed

Pour finir il faut connecter notre bouton pour appeler notre fonction cb_quit lorsque lutilisateur clic dessus (ce quicorrespond agrave leacuteveacutenement clicked)

g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_quit) NULL)

Pour eacuteviter dappeler la fonction gtk_widget_show pour tous les widgets de notreapplication on peut se contenter dun seul appel agrave la fonction gtk_widget_show_all quipermet dafficher tous les widgets contenus dans celui passeacute agrave la fonction

maincinclude ltstdlibhgtinclude ltgtkgtkhgtinclude callbackh

int main (int argc char argv) GtkWidget p_window = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (cb_quit) NULL)

GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_QUIT) gtk_container_add (GTK_CONTAINER (p_window) p_button) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_quit) NULL)

Affichage de la fenetre principale gtk_widget_show_all (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

III-C - Code source

chapitre3zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 13 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IV - Comment afficher plusieurs widgets

IV-A - Aperccedilu

IV-B - Le problegraveme

Dans la partie preacuteceacutedente nous avons reacuteussi agrave afficher un bouton dans la fenecirctre de notre application Si vous avezessayeacute dajouter un second widget GTK+ agrave ducirc vous reacutepondre poliment

(gtk_boxexe492) Gtk-WARNING Attempting to add a widget with typeGtkButton to a GtkWindow but as a GtkBin subclass a GtkWindow can only containone widget at a time it already contains a widget of type GtkButton

Les plus anglophiles dentre vous auront compris que GTK+ naccepte pas lajout un second widget dans notre fenecirctretout simplement parce quil y en a deacutejagrave un et que la sous classe GtkBin (classe megravere de notre GtkWindow) ne peutcontenir quun seul widget

IV-C - La solutions

Pour contourner ce problegraveme il faut commencer par creacuteer un widget qui accepte den contenir plusieurs autrespour ensuite y ajouter tout ce dont nous avons besoin Pour linstant nous utiliserons quun seul widget (il existetrois classes qui permettent ceci) il sagit des GtkBox Il sagit de la meacutethode que jutilise le plus souvent Ce nestpeut-ecirctre pas la plus simple agrave maicirctriser mais elle extrecircmement souple et puissante Elle consiste agrave creacuteer une boicirctepuis agrave y ajouter les widgets les uns apregraves les autres (soit au deacutebut soit agrave la fin) Il existe deux classes heacuteritant deGtkBox les GtkVBox qui empilent les widgets dans le sens vertical et les GtkHBox qui font de mecircme mais dansle sens horizontal Les fonctions pour manipuler ces deux classes sont les mecircmes seule la fonction pour les creacuteerportent un nom diffeacuterent

GtkWidget gtk_vbox_new (gboolean homogeneous gint spacing)GtkWidget gtk_hbox_new (gboolean homogeneous gint spacing)

Le paramegravetre homogeneous permet de reacuteserver pour chaque widget une zone de taille identique (zone que le widgetnest pas obligeacute de remplir) et spacing permet dajouter une bordure en pixels (espacement autour de la GtkBox)Ensuite il suffit dajouter les diffeacuterents widgets gracircce aux fonctions

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)

Qui ajoutent reacuteciproquement le widget child au deacutebut et agrave la fin de box Le paramegravetre expand permet au widget davoirle plus de place possible (si le paramegravetre homogeneous vaut TRUE cette option a aucun effet) Si plusieurs widgetont ce paramegravetre agrave TRUE ils se partagent de faccedilon eacutegale lespace Loption fill permet au widget de remplir toutlespace qui lui ait reacuteserveacute

Pour reacuteellement comprendre linfluence de ces paramegravetres il faut faire des tests en modifiant un agrave un chaqueparamegravetre et observer les effets dun redimentionnement de la fenecirctre principale

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 14 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Le plus gecircnant avec cette meacutethode cest quil faut jongler entre les GtkHBox et les GtkVBox en les imbriquant pourobtenir le reacutesultat souhaiter nheacutesitez pas agrave utiliser une feuille et un crayon )

Pour en revenir agrave notre eacutediteur de texte nous allons preacuteparer notre application agrave contenir les futurs widgetsNous utilisons un GtkVBox pour lensemble des widgets (il sagit de la boicircte principale qui pourra contenir dautresGtkContainer selon nos besoins)

maincinclude ltstdlibhgtinclude ltgtkgtkhgtinclude callbackh

int main (int argc char argv) GtkWidget p_window = NULL GtkWidget p_main_box = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (cb_quit) NULL)

Creation du conteneur principal p_main_box = gtk_vbox_new (FALSE 0) gtk_container_add (GTK_CONTAINER (p_window) p_main_box)

Creation du bouton Quitter GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_QUIT) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_quit) NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_button FALSE FALSE 0)

Affichage de la fenetre principale gtk_widget_show_all (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

IV-D - Code source

chapitre4zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 15 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

V - Afficher le contenue dun fichier

V-A - Aperccedilu

Cliquez pour agrandir

V-B - Saisir du texte

Les choses seacuterieuses vont commencer il sagit de mettre en place le widget qui va nous permettre dafficher etdeacutediter du texte Il sagit de la classe GtkTextView Gracircce agrave GTK+ la mise en place est toujours aussi simple

mainc GtkWidget p_text_view = NULL Creation de la zone de texte p_text_view = gtk_text_view_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_text_view TRUE TRUE 0)

Comme il sagit de la partie centrale de notre application nous demandons agrave ce quelle prenne le plus de placepossible (gracircce agrave la fonction gtk_box_pack_start)

Puisque nous voulons afficher les boutons en dessous de la zone de texte il faut ajouter ce morceau de code avantcelui creacuteant le bouton

V-C - Ouvrir un fichier

Maintenant nous avons une belle zone de texte il faut la remplir avec le contenu dun fichier Pour ce faire nousallons commencer par ajouter un bouton ouvrir

mainc Creation du bouton Ouvrir GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_OPEN) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_open) p_text_view) gtk_box_pack_start (GTK_BOX (p_main_box) p_button FALSE FALSE 0)

Si vous exeacutecutez le programme maintenant (3) vous remarquerez que les boutons sont ajouteacutes les uns en dessousdes autres ce qui diminue la zone de saisie (avec deux boutons ce nest pas gecircnant mais au bout dune dizaineccedila risque decirctre probleacutematique) Pour pallier ce problegraveme nous allons utiliser un nouveau style de GtkBox lesGtkButtonBox qui sont preacutevus pour contenir des boutons (ccedila tombe plutocirct bien D) Donc pour eacuteviter de diminuerla zone de saisie et comme nous avons de la place en largueur nous allons utiliser un GtkHButtonBox qui va ecirctreinclus dans la p_main_box Voici les modifications agrave effectuer

mainc GtkWidget p_button_box = NULL Creation du conteneur pour les boutons p_button_box = gtk_hbutton_box_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_button_box FALSE FALSE 0)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 16 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc gtk_box_pack_start (GTK_BOX (p_button_box) p_button FALSE FALSE 0) gtk_box_pack_start (GTK_BOX (p_button_box) p_button FALSE FALSE 0)

Maintenant il nous reste plus quagrave creacuteer la fonction cb_open dans le fichier callbackc pour linstant nous nouscontenterons douvrir toujours le mecircme fichier nous verrons plus tard comment laisser le choix agrave lutilisateur

callbackcdefine DEFAULT_FILE mainc

void cb_open (GtkWidget p_widget gpointer user_data) open_file (DEFAULT_FILE GTK_TEXT_VIEW (user_data))

Parametre inutilise (void)p_widget

Vous aurez compris que lon va deacuteleacuteguer tout le travail agrave la fonction open_file qui devra ouvrir le fichier dont le nomest passeacute en premier paramegravetre pour lafficher dans le GktTextView

Jai fait ce choix pour deux raisons le code dune fonction callback peut ecirctre tregraves conseacutequent (surtout si lon souhaitequelle affiche une boicircte de dialogue) et aussi parce que cb_open nest peut ecirctre pas la seule fonction agrave copierun fichier dans un GtkTextView (par exemple lors de la creacuteation dun nouveau fichier lon peut vouloir copier unsquelette de fichier)

Pour copier notre fichier plutocirct que dutiliser la fonction fgets nous allons nous servir de la glib (4) qui proposela fonction

gboolean g_file_get_contents (const gchar filename gchar contents gsize length GError error)

Qui nous renvoit le contenu du fichier nommeacute filename dans le tampon contents Il est possible de reacutecupeacuterer lenombre de caractegraveres copieacutes et retourne TRUE en cas de succegraves sinon FALSE et dans ce cas une structure de typeGError est creacutee pour en savoir plus sur le type derreur rencontreacute

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView else print_warning (Impossible douvrir le fichier sn file_name)

Je pense quun certain nombre dexplications simpose (surtout si je vais trop vite nheacutesitez pas agrave marrecircter )

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 17 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

bull g_return_if_fail est une macro qui peut ecirctre compareacutee agrave assert sauf quelle se contente de sortir de la fonctionsi lexpression passeacutee en paramegravetre est fausse Cest une meacutethode pratique pour veacuterifier la validiteacute desparamegravetres (si la fonction doit retourne une valeur utiliseacute plutocirct g_return_val_if_fail qui prend un secondparamegravetre la valeur agrave retourner)

bull Ensuite on essaie de reacutecupeacuterer le contenu de notre fichier

bull Si cela eacutechoue nous le signalons agrave lutilisateur agrave laide de la fonction print_warning

bull Le type gchar est une redeacutefinition du type char par la glib (il en va de mecircme pour tous les autres types du C)privileacutegiez ces types lorsque vous utilisez des fonctions de cette bibliothegraveques

Mais quest-ce donc cette fonction print_warning Cest une fonction que nous allons creacuteer semblable agrave printf quisignalera agrave lutilisateur quune erreur non critique est survenue Comme nous navons pas encore abordeacute les boicirctesde dialogue pour afficher un message il sagira pour linstant dune simple redeacutefinition de printf Pendant que noussommes dans laffichage des messages nous allons aussi creacuteer deux fonctions print_info et print_error qui vontrespectivement afficher un message dinformation et un message derreur critique (ce qui entraicircne la terminaison duprogramme) tout ceci dans un nouveau fichier errorc

errorhifndef H_ERRORdefine H_ERROR

void print_info (char )void print_warning (char )void print_error (char )

endif not H_ERROR

errorcinclude ltstdarghgtinclude ltstdiohgtinclude ltstdlibhgtinclude errorh

void print_info (char format ) va_list va

va_start (va format) printf (Information ) vprintf (format va) printf (n)

void print_warning (char format ) va_list va

va_start (va format) fprintf (stderr Erreur ) vfprintf (stderr format va) fprintf (stderr n)

void print_error (char format ) va_list va

va_start (va format) fprintf (stderr Erreur fatale ) vfprintf (stderr format va) fprintf (stderr n) exit (EXIT_FAILURE)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 18 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

Pour en finir avec louverture dun fichier il nous reste agrave copier contents dans le GtkTextView En fait le GtkTextViewne gegravere que la forme pour modifier le contenu il faut passer par les GtkTextBuffer Commenccedilons donc par reacutecupeacutererce fameux GtkTextBuffer

callbackc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (p_text_view)

Et pour finir on utilise la fonction

void gtk_text_buffer_insert (GtkTextBuffer buffer GtkTextIter iter const gchar text gint len)

Reacutecapitulons buffer est le GtkTextBuffer que lon vient de reacutecupeacuterer text cest le texte agrave afficher et len la taille dece dernier (ou -1 sil sagit dune chaicircne de caractegraveres au sens du langage C)

Mais quest-ce donc ce GtkTextIter On peut voir cela comme un curseur virtuel qui indique la position agrave laquelleeffectuer linsertion de texte dans le GtkTextBuffer (5) Allons voir ce que la documentation peut nous apprendreagrave leur sujet (6)

typedef struct GtkTextIter is an opaque datatype ignore all these fields Initialize the iter with gtk_text_buffer_get_iter_ functions GtkTextIter

Voilagrave on a notre solution suffit de rechercher les fonctions commenccedilant par gtk_text_buffer_get_iter_ voici la liste

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)

La fonction gtk_text_buffer_get_iter_at_line fait parfaitement laffaire

callbackc GtkTextIter iter

gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1)

Cependant si vous ne voulez pas avoir de problegravemes avec le codage des caractegraveres il vaut mieux convertir le codagelocal vers utf8 Voici le reacutesultat final

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 19 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gchar utf8 = NULL GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_text_buffer_insert (p_text_buffer ampiter utf8 -1) g_free (utf8) utf8 = NULL

V-D - La petite touche finale

Pour finir cette laborieuse partie sur une petite touche estheacutetique nous allons demander agrave GTK+ de nous lancerlapplication en plein eacutecran Pour se faire il suffit dajouter lors de la creacuteation de la fenecirctre principale

maincgtk_window_maximize (GTK_WINDOW (p_window))

On peut mecircme se permettre une pointe dexcentriciteacute en modifiant le titre de notre fenecirctre

maincgtk_window_set_title (GTK_WINDOW (p_window) Editeur de texte en GTK+)

V-E - Code source

chapitre5zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 20 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VI - Choisir un fichier

VI-A - Aperccedilu

Cliquez pour agrandir

VI-B - Utilisation dun GtkFileChooserFile

Jusquagrave preacutesent lutilisateur navait pas le choix quant au fichier agrave ouvrir heureusement GTK+ vient agrave notre aide gracircceau widget GtkFileChooserFile qui est tout simplement une boicircte de dialogue qui propose agrave lutilisateur de seacutelectionnerun fichier dans son arborescence disque

Commenccedilons par creacuteer notre boicircte de dialogue dans la fonction cb_open

callbackcvoid cb_open (GtkWidget p_widget gpointer user_data) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Ouvrir un fichier NULL GTK_FILE_CHOOSER_ACTION_OPEN GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_OPEN GTK_RESPONSE_ACCEPT NULL)

Cette fonction neacutecessite le titre de la boicircte de dialogue une fenecirctre parente le type daction (ici on souhaite ouvrir unfichier GTK+ autorisera lutilisateur agrave seacutelectionner uniquement les fichiers existants) Pour finir il sagit dun couple devaleurs GTK_STOCK_ITEMGTK_STOCK_RESPONSE qui permet de creacuteer un bouton utilisant le stock ID speacutecifieacuteet lorsque celui-ci est cliqueacute la fonction servant agrave lancer la boicircte de dialogue retournera le reacuteponse ID correspondantIl existe une seacuterie de valeurs deacutefinies par GTK+ quil est conseilleacute dutiliser

typedef enum GTK returns this if a response widget has no response_id or if the dialog gets programmatically hidden or destroyed GTK_RESPONSE_NONE = -1

GTK wont return these unless you pass them in as the response for an action widget They are for your convenience GTK_RESPONSE_REJECT = -2 GTK_RESPONSE_ACCEPT = -3

If the dialog is deleted GTK_RESPONSE_DELETE_EVENT = -4

These are returned from GTK dialogs and you can also use them yourself if you like GTK_RESPONSE_OK = -5 GTK_RESPONSE_CANCEL = -6 GTK_RESPONSE_CLOSE = -7 GTK_RESPONSE_YES = -8

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 21 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GTK_RESPONSE_NO = -9 GTK_RESPONSE_APPLY = -10 GTK_RESPONSE_HELP = -11 GtkResponseType

Nous indiquons la fin des couples stock idreacuteponse id avec la valeur NULL

Une fois la boicircte de dialogue creacuteee on demande agrave GTK+ de lafficher gracircce agrave la fonction gtk_dialog_run puis onreacutecupegravere sa valeur de retour qui correspond au bouton cliqueacute par lutilisateur

callbackc if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

Ici ce qui nous inteacuteresse cest lorsque que lutilisateur clique sur le bouton ouvrir (donc gtk_dialog_run renvoieGTK_RESPONSE_ACCEPT) dans ce cas il nous suffit de reacutecupeacuterer le nom du fichier seacutelectionneacute puis de louvrir

callbackc gchar file_name = NULL

file_name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) open_file (file_name GTK_TEXT_VIEW (user_data)) g_free (file_name) file_name = NULL

Pour finir dans tous les cas on noublie pas de deacutetruire la boicircte de dialogue

callbackc gtk_widget_destroy (p_dialog)

Et voilagrave le travail lutilisateur peut ouvrir le fichier quil souhaite

VI-C - Code source

chapitre6zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 22 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VII - Interlude

Avant daller plus loin dans lameacutelioration de linterface de notre eacutediteur il est neacutecessaire de modifier sonfonctionnement interne (ne vous inquieacutetez je nai pas dit chambouler) en effet souvenez-vous dans lintroduction jaieacutevoqueacute la possibiliteacutes douvrir plusieurs documents gracircce agrave un systegraveme donglets Pour cela il faut sauvegarder lesproprieacuteteacutes de chaque document ouvert Pris agrave temps ce genre de modification nest pas trop lourde mais si nousattendons cela risque de devenir un vrai casse tecircte

Pour cela nous allons utiliser une structure de donneacutee pour chaque document ouvert qui devra garder en meacutemoirele chemin complet du fichier (ou NULL si le document nest pas encore sauvegarder) sil agrave eacutetait modifier depuis laderniegravere sauvegarde et le GtkTextView qui sert agrave son affichage Voici donc la structure qui va nous servir

documenthtypedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

Sachant que nous serons ameneacute agrave stocker plusieurs occurrences de cette structure il serait bon de reacutefleacutechir degravesmaintenant agrave la structure de donneacutee agrave utiliser pour les stocker La premiegravere ideacutee qui vient agrave lesprit est un tableaualloueacute dynamiquement cependant lutilisateur peut souhaiter fermer un document qui se trouve au milieu on estalors obligeacute de deacutecaler toutes les cellules en amont Dans ce cas il parait naturel dutiliser une liste chaicircneacutee Parchance la glib propose une bibliothegraveque de gestion des listes chaicircneacutees cela nous fera gagner du temps le momentvenu Pour linstant on se contente de creacuteer une structure de donneacutees qui contiendra tous les documents ouverts(stockeacutee dans une GList) et un pointeur sur le document actif (actuellement comme nous navons quun documentouvert en mecircme temps on manipulera uniquement ce pointeur)

documenthtypedef struct GList tous document_t actif docs_t

Maintenant se pose le problegraveme de savoir comment transmettre cette structure On pourrait se servir du paramegravetreuser_data preacutesent dans toutes les fonctions callback mais certaines fonctions utilise deacutejagrave ce paramegravetre (la fonctioncb_open par exemple) il faudrait creacuteer un champs suppleacutementaire dans notre structure documents_s Une solutionplus simple est de creacuteer une variable globale agrave lensemble du programme Ceux qui passe reacuteguliegraverement sur le forumC savent que cest fortement deacuteconseilleacute mais ici nous nous trouvons dans lune des rares exceptions agrave la regravegle Detoute faccedilon cela revient au mecircme que de passer ladresse de notre structure agrave toutes les fonctions callback Nousdeacutefinissons donc un nouveau fichier den-tecircte

documenthifndef H_DOCUMENTdefine H_DOCUMENT

include ltgtkgtkhgt

typedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 23 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

documenthtypedef struct GList tous document_t actif docs_t

extern docs_t docs

endif not H_DOCUMENT

Et dans le fichier mainc

maincinclude documenth

docs_t docs = NULL NULL

Pour linstant la seule fonction qui modifie leacutetat dun document est la fonction open_file il faut donc inclure documenthdans callbackc et modifier leacutegegraverement la fonction pour enregistrer le document ouvert

callbackc if (g_file_get_contents (file_name ampcontents NULL NULL)) Pour linstant il faut allouer la memoire par la suite on modifira simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = g_strdup (file_name) Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = p_text_view Le document vient detre ouvert il nest donc pas modifie docsactif-gtsauve = TRUE

Ne soyez pas choqueacute si je ne teste pas le retour de la fonction g_malloc pour veacuterifier quilnest pas NULL En effet cette derniegravere met fin agrave lapplication si lallocation eacutechoue

VII-A - Code source

chapitre7zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 24 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VIII - Sauvegarder les modification

VIII-A - Aperccedilu

Cliquez pour agrandir

VIII-B - Enregistrer

Avant de pouvoir sauvegarder un document il faut quil soit modifieacute Comment savoir que le contenu du fichier a eacuteteacutemodifier Gracircce au signal changed du GtkTextBuffer que nous interceptons gracircce agrave la fonction cb_modifie

mainc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (p_text_view)) g_signal_connect (G_OBJECT (p_text_buffer) changed G_CALLBACK (cb_modifie) NULL)

Cette derniegravere modifie simplement le champ sauve du document

callbackcvoid cb_modifie (GtkWidget p_widget gpointer user_data) if (docsactif) docsactif-gtsauve = FALSE

Pour la sauvegarde il faut distinguer deux cas soit il sagit de la premiegravere sauvegarde du fichier il faut alors demanderle nom du fichier agrave lutilisateur (cela ressemble fortement agrave louverture dun fichier) soit le fichier est deacutejagrave preacutesent surle disque il suffit de remplacer son contenu par celui du GtkTextViewer Nous avons convenu quun fichier qui neacutetaitpas encore enregistreacute avait sa proprieacuteteacute chemin agrave NULL

Bien sucircr cela na lieu que si un fichier est ouvert et quil a eacuteteacute modifieacute depuis sa derniegravere sauvegarde

callbackcvoid cb_save (GtkWidget p_widget gpointer user_data) if (docsactif) if (docsactif-gtsauve) Le fichier na pas encore ete enregistre if (docsactif-gtchemin) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Sauvegarder le fichier NULL GTK_FILE_CHOOSER_ACTION_SAVE GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_SAVE GTK_RESPONSE_ACCEPT NULL) if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 25 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc docsactif-gtchemin = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) gtk_widget_destroy (p_dialog) Soit le fichier a deja ete enregistre soit lutilisateur vient de nous fournir son nouvel enplacement on peut donc lenregistrer if (docsactif-gtchemin) else print_warning (Aucun document ouvert)

Il nous reste plus quagrave reacutecupeacuterer le contenu du GtkTextViewer et le copier dans le fichier chemin sans oublier dereconvertir le texte dans le codage local

callbackc FILE fichier = NULL

fichier = fopen (docsactif-gtchemin w) if (fichier) gchar contents = NULL gchar locale = NULL GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) contents = gtk_text_buffer_get_text (p_text_buffer ampstart ampend FALSE) locale = g_locale_from_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL fprintf (fichier s locale) g_free (locale) locale = NULL fclose (fichier) fichier = NULL docsactif-gtsauve = TRUE else print_warning (Impossible de sauvegarder le fichier s docsactif-gtchemin)

Le dernier paramegravetre de la fonction gtk_text_buffer_get_text est mis agrave FALSE car nous ne voulons pas enregistrerles caractegraveres invisibles preacutesent dans le GtkTextBuffer Ces caractegraveres servent agrave mettre en forme le texte (taillecouleur) nous pourrions creacuteer un nouveau format de fichier pour enregistrer la mise en forme

VIII-C - Enregistrer sous

Pour enregistrer notre document sous un autre nom il suffit de faire croire agrave cb_save que le document na pas encoreeacutetait enregistreacute tout simplement en changeant chemin agrave NULL et sauve agrave FALSE

callbackcvoid cb_saveas (GtkWidget p_widget gpointer user_data)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 26 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (docsactif) document_t tmp = docsactif

docsactif-gtchemin = NULL docsactif-gtsauve = FALSE cb_save (p_widget user_data) if (docsactif-gtsauve) (docsactif) = tmp else print_warning (Aucun document ouvert)

Il ne faut pas oublier que lutilisateur peut annuler lenregistrement de ce fait nous sauvegardons leacutetat du documentet si la sauvegarde na pas eu lieu on le restaure

VIII-D - Code source

chapitre8zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 27 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IX - Creacuteer un nouveau document

IX-A - Aperccedilu

Cliquez pour agrandir

IX-B - Nouveau fichier

Maintenant que lutilisateur peut ouvrir et fermer un fichier il est inteacuteressant de lui donner la possibiliteacute den creacuteerun nouveau Je ne reviens pas sur la creacuteation du bouton (ccedila devrait deacutejagrave ecirctre fait D) passons directement agrave lafonction cb_new

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) Pour linstant il faut allouer la memoire par la suite on modifiera simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = NULL Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = GTK_TEXT_VIEW (user_data) Le document vient detre creer il nest donc pas modifie docsactif-gtsauve = TRUE gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Je ne sais pas vous mais pour ma part jai fait un copiercoller de la fonction open_file Et oui ouvrir un document peutse reacutesumer agrave creacuteer un document vide puis remplir le GtkTextView avec le fichier souhaiteacute On peut donc simplifiernotre fonction open_file ainsi

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

cb_new (NULL p_text_view) gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE) p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1) Nous sommes obliges de remetre sauve a TRUE car linsertion du contenu du fichier dans le GtkTextView a appele cb_modfie docsactif-gtsauve = TRUE else print_warning (Impossible douvrir le fichier sn file_name)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 28 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc

Cest beau la factorisation du code Par contre nous sommes obligeacutes de remettre sauve agrave TRUE car nous avonsmodifieacute le GtkTextBuffer

IX-C - Code source

chapitre9zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 29 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

X - Fermer

X-A - Aperccedilu

Cliquez pour agrandir

X-B - Fermer un fichier

Maintenant que nous allouons de la meacutemoire il faut la libeacuterer agrave un endroit Logiquement cela va ecirctre fait agrave la fermeturedu document en guise dexercice je vous laisse creacuteer le bouton dans notre boicircte agrave bouton

Allez je vous aide le stock id correspondant est GTK_STOCK_CLOSE

Voilagrave maintenant si tout cest bien passeacute vous devriez ecirctre arriveacute dans le fichier callbackc avec quelque choseressemblant agrave

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data)

Lorsque lon ferme un document il faut vider le GtkTextView (avec les onglets on se contentera de le supprimer)pour cela il faut reacutecupeacuterer le deacutebut et la fin du GtkTextBuffer et demander agrave GTK+ de supprimer tout ce qui ce trouveentre les deux iteacuterateurs

callbackc Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) gtk_text_buffer_delete (p_text_buffer ampstart ampend) else print_warning (Aucun document ouvert)

Bien sucircr il ne faut pas oublier de libeacuterer la meacutemoire

callbackc g_free (docsactif-gtchemin) docsactif-gtchemin = NULL docsactif-gtp_text_view = NULL g_free (docsactif) docsactif = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 30 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour symboliser la fermeture dun document nous deacutesactivons le GtkTextView lors de la fermeture (ne pas oublierde le faire aussi dans mainc)

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) FALSE)

Et nous le reacuteactivons lors de louverture si celle si reacuteussie

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Lorsque lutilisateur quitte lapplication il faut bien sucircr fermer le document sil y en a un ouvert

void cb_quit (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data) gtk_main_quit()

Et aussi lorsquil creacuteeacute un nouveau document (et par conseacutequent lorsquil ouvre un fichier puisque lon fait appel agravecb_new)

void cb_new (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data)

X-C - Enregistrer avant de fermer

Si le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde geacuteneacuteralement le programme le signale agrave lutilisateur etlui propose de sauvegarder ou dannuler la fermeture Pour se faire nous devons modifier la fonction cb_close avantde fermer le document nous allons afficher une boicircte de dialogue

Pour creacuteer une boicircte de dialogue simplement il existe la classe GtkDialog et comme nous avons besoin de boutons(pour que lutilisateur fasse son choix) nous allons creacuteer notre boicircte avec la fonction

GtkWidget gtk_dialog_new_with_buttons (const gchar title GtkWindow parent GtkDialogFlags flags const gchar first_button_text )

Nous retrouvons les mecircmes options que pour le GtkFileChooserDialog mis agrave part option du type GtkDialogFlags

typedef enum GTK_DIALOG_MODAL = 1 ltlt 0 appel gtk_window_set_modal (win TRUE) GTK_DIALOG_DESTROY_WITH_PARENT = 1 ltlt 1 appel gtk_window_set_destroy_with_parent () GTK_DIALOG_NO_SEPARATOR = 1 ltlt 2 Pas de barre de separation au dessus des boutons GtkDialogFlags

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 31 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Nous nous contenterons de rendre notre fenecirctre modale (7)

Pour avoir accegraves agrave notre fenecirctre principale nous ajoutons un champs p_main_window agrave notre structure globaledocs_t que nous initialisons dans la fonction main

mainc docsp_main_window = GTK_WINDOW (p_window)

Il nous reste plus qua creacuteer notre boicircte de dialogue avec trois boutons Oui Non Annuler

callbackc if (docsactif-gtsauve) GtkWidget p_dialog = NULL

p_dialog = gtk_dialog_new_with_buttons (Sauvegarder docsp_main_window GTK_DIALOG_MODAL GTK_STOCK_YES GTK_RESPONSE_YES GTK_STOCK_NO GTK_RESPONSE_NO GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL NULL)

Nous obtenons donc une structure de type GtkDialog

typedef struct GtkWidget vbox GtkWidget action_area GtkDialog

Nous remarquons que cette structure contient deux membres qui permettent dacceacuteder agrave une GtkBox ougrave nous allonsajouter le contenu de la fenecirctre et agrave la partie contenant les boutons

Ensuite la construction de la fenecirctre est identique agrave celle de la fenecirctre principale ici nous nous contenterons dajouterun GtkLabel

callbackc GtkWidget p_label = NULL p_label = gtk_label_new (Voulez-vous sauvegarder les modifications ) gtk_box_pack_start (GTK_BOX (GTK_DIALOG (p_dialog)-gtvbox) p_label TRUE TRUE 0)

Une fois notre fenecirctre precircte il suffit de faire appel agrave la fonction gtk_dialog_run qui va afficher notre GtkDialog et nousretourner le reacuteponse id correspondant au bouton cliqueacute par lutilisateur

callbackc switch (gtk_dialog_run (GTK_DIALOG (p_dialog))) case GTK_RESPONSE_YES cb_save (p_widget user_data) break case GTK_RESPONSE_NO break case GTK_RESPONSE_CANCEL gtk_widget_destroy (p_dialog) return break

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 32 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc gtk_widget_destroy (p_dialog)

Si lutilisateur clique sur non on ne fait rien (le document sera simplement fermeacute) sur oui on enregistre avant defermer et pour finir sil annule on quitte la fonction

X-D - Code source

chapitre10zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 33 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XI - Les barres de deacutefilement

XI-A - Aperccedilu

Cliquez pour agrandir

XI-B - Ajouter des barres de deacutefilement

Apregraves le dernier chapitre quelque peu laborieux voici une partie plus simple mais qui va rendre notre applicationplus pratique En effet si vous avez essayeacute douvrir un fichier de grande taille vous avez pu remarquer que pourpouvoir lire la fin du fichier il fallait utiliser les touches du clavier pas tregraves convivial

Pour rendre la navigation plus aiseacutee on utilise des barres de deacutefilement

mainc GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_scrolled_window TRUE TRUE 0)

Creation de la zone de texte gtk_container_add (GTK_CONTAINER (p_scrolled_window) p_text_view)

Le constructeur de notre GtkScrolledWindow prend en argument deux GtkAdjustment qui permettent de deacutefinirdiffeacuterentes proprieacuteteacutes de la barre de deacutefilement (taille dune page la position de deacutepart) nous laissons GTK+ faireen passant NULL

Cest un bon deacutebut mais estheacutetiquement on peut faire mieux mecircme sil nest pas utile davoir une barre de deacutefilementelle est quand mecircme afficheacutee On peut demander agrave GTK+ de les afficher que si cela est neacutecessaire

mainc gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC)

En fait nous avons de la chance car la classe GtkTextView fait partie des widget qui supporte de faccedilon native les barresde deacutefilement Comment le savoir Ce genre de widget possegravede une ou deux proprieacuteteacutes de type GtkAdjustment (unepour la barre verticale lautre pour la barre horizontale) Actuellement seulement trois classes en sont capables lesGtkTextView les GtkTreeView et les GtkLayout

Comment faire pour les autres widgets Il faut passer par une classe adaptateur GtkViewport afin de creacuteer lesGtkAdjustment

XI-C - Code source

chapitre11zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 34 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XII - Les menus

XII-A - Aperccedilu

Cliquez pour agrandir

XII-B - Creacuteation du menu

Pour simplifier nous avons utiliseacute des boutons pour permettre agrave lutilisateur de creacuteer un document ouvrir un fichierMais il est plus courant dutiliser un menu pour afficher ces options GTK+ propose trois maniegraveres de creacuteer un menu

bull GtkItemFactory cette meacutethode est obsolegravete depuis la version 24 de GTK+

bull GtkUIManager cest ce quon appel une usine agrave gaz pour en savoir plus vous pouvez vous reporter aututoriel Utilisation de GtkUIManager

bull GtkMenu cest ce widget que nous allons eacutetudier il permet de creacuteer un menu manuellement (agrave lopposeacute deGtkUIManager)

Un menu selon GTK+ est composeacute de plusieurs eacuteleacutements

bull GtkMenuBar la barre de menu elle-mecircme

bull GtkMenu la partie deacuteroulante qui contient les diffeacuterents eacuteleacutements

bull GtkMenuItem cest sur ce widget que lutilisateur clique pour lancer une action

Pour commencer faisons linventaire de ce que nous avons besoin

bull Un GtkMenuBar qui sert de base au menu

bull Un GtkMenu pour commencer nous nous aurons dun menu Fichier

bull Six GtkMenuItem pour remplacer nos six boutons

Commenccedilons par la creacuteation du menu nous mettons ce code dans un nouveau fichier dont seul la fonction menu_newsera accessible

menucGtkMenuBar menu_new (gpointer user_data) GtkWidget p_menu_bar = NULL

p_menu_bar = gtk_menu_bar_new () return GTK_MENU_BAR (p_menu_bar)

Le paramegravetre user_data nous servira lors de la connexion des callbacks (nous en avons besoin pour les fonctionscb_new et cb_open)

Ensuite nous allons creacuteer notre sous menu Fichier

menuc Menu Fichier

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 35 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

menuc GtkWidget p_menu = NULL GtkWidget p_menu_item = NULL

p_menu = gtk_menu_new () p_menu_item = gtk_menu_item_new_with_mnemonic (_Fichier) gtk_menu_item_set_submenu (GTK_MENU_ITEM (p_menu_item) p_menu) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu_bar) p_menu_item) return GTK_MENU_BAR (p_menu_bar)

Un sous menu est en fait un GtkMenuItem auquel on assigne un GtkMenu Il faut bien sucircr terminer la creacuteation dusous-menu en lajoutant agrave la barre de menu

Pour finir nous creacuteons les eacuteleacutements du menu les GtkItemMenu Il existe plusieurs types deacuteleacutements (comparableaux diffeacuterents types de bouton) pour commencer nous nutiliserons que le type de base Comme cette opeacuteration estreacutepeacutetitive nous allons creacuteer une fonction pour le faire

menucstatic void menu_item_new (GtkMenu p_menu const gchar title GCallback callback gpointer user_data) GtkWidget p_menu_item = NULL

p_menu_item = gtk_menu_item_new_with_mnemonic (title) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu) p_menu_item) g_signal_connect (G_OBJECT (p_menu_item) activate callback user_data)

Pour permettre agrave lutilisateur dacceacuteder aux diffeacuterents eacuteleacutements du menu agrave laide de la touche ltAltgt nous utilisonsdes mneacutemoniques par exemple pour quitter leacutediteur il suffit de faite Alt+F puis Q Et voici le code pour creacuteer nossix eacuteleacutements du menu

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau G_CALLBACK (cb_new) user_data) menu_item_new (GTK_MENU (p_menu) _Ouvrir G_CALLBACK (cb_open) user_data) menu_item_new (GTK_MENU (p_menu) _Enregistrer G_CALLBACK (cb_save) user_data) menu_item_new (GTK_MENU (p_menu) Enregistrer _sous G_CALLBACK (cb_saveas) user_data) menu_item_new (GTK_MENU (p_menu) _Fermer G_CALLBACK (cb_close) user_data) menu_item_new (GTK_MENU (p_menu) _Quitter G_CALLBACK (cb_quit) user_data)

Voilagrave notre menu est creacuteeacute il nous reste plus quagrave linteacutegrer agrave notre fenecirctre

mainc gtk_box_pack_start (GTK_BOX (p_main_box) GTK_WIDGET (menu_new (p_text_view)) FALSE FALSE 0)

Le problegraveme cest que nous avons besoin de passer le GtkTextView lors de la creacuteation du menu (qui est utiliseacute par lesfonctions cb_new et cb_open) or celui-ci est creacuteeacute apregraves le menu (puisque nous creacuteons les widgets dans lordre ougrave ilfaut les inteacutegrer agrave linterface (8) ) nous devons creacuteer le GtkTextView (seul lappel agrave gtk_text_view_new est deacuteplaceacute)

XII-C - Code source

chapitre12zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 36 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIII - Les barres doutils

XIII-A - Aperccedilu

Cliquez pour agrandir

XIII-B - Creacuteation dune barre doutils

La creacuteation dune barre doutils ressemble fort agrave celle dun menu en plus simple puisquil ny a pas de sous menu on creacutee notre barre doutils (gtk_toolbar_new) puis les eacuteleacutements de la barre pour cela on utilise des boutons(gtk_tool_button_new_from_stock) que lon inseacutere dans la barre (gtk_toolbar_insert) Pas conseacutequent notre fichierbarreoutilsc ressemble agrave menuc

barreoutilscinclude ltgtkgtkhgtinclude callbackhinclude barreoutilsh

static void toolbar_item_new (GtkToolbar const gchar GCallback gpointer)

GtkToolbar toolbar_new (gpointer user_data) GtkWidget p_toolbar = NULL

p_toolbar = gtk_toolbar_new () toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_NEW G_CALLBACK (cb_new) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_OPEN G_CALLBACK (cb_open) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE G_CALLBACK (cb_save) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE_AS G_CALLBACK (cb_saveas) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_CLOSE G_CALLBACK (cb_close) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_QUIT G_CALLBACK (cb_quit) user_data) return GTK_TOOLBAR (p_toolbar)

static void toolbar_item_new (GtkToolbar p_toolbar const gchar stock_id GCallback callback gpointer user_data) GtkToolItem p_tool_item = NULL

p_tool_item = gtk_tool_button_new_from_stock (stock_id) g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data) gtk_toolbar_insert (p_toolbar p_tool_item -1)

Le code nest pas complet car lorsque jexeacutecute le programme GTK+ affiche en plus des icocircnes le texte sous lesboutons Pour modifier cela il suffit dajouter une ligne de code

barreoutilsc gtk_toolbar_set_style (GTK_TOOLBAR (p_toolbar) GTK_TOOLBAR_ICONS)

Pourquoi gtk_tool_button_new_from_stock retourne un GtkToolItem et non un GtkWidgetcomme nous avons eacuteteacute habitueacute jusquagrave preacutesent Il sagit dune bizarrerie de GTK+ dontje ne connais pas la raison

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 37 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour anticiper un changement dinterface (dans GTK+ 30 peut ecirctre ) nous aurions pueacutecrire

Gtkwidget p_tool_item = NULL

p_tool_item = GTK_WIDGET (gtk_tool_button_new_from_stock (stock_id))g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data)gtk_toolbar_insert (p_toolbar GTK_TOOL_ITEM (p_tool_item) -1)

XIII-C - Code source

chapitre13zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 38 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIV - Les racourcis clavier

XIV-A - Aperccedilu

Cliquez pour agrandir

XIV-B - Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mneacutemoniques ces derniers permettent dacceacuteder agrave un eacuteleacutementseacutequentiellement alors que les raccourcis appellent une fonction si lutilisateur appuie simultaneacutement sur une ouplusieurs touches (geacuteneacuteralement de la forme ltModificateurgtTouche ougrave Modificateur repreacutesente les touches ShiftAlt et Control) Ce raccourci peut ecirctre attacheacute agrave un eacuteleacutement du menu mais ceci nest pas obligatoire

Les raccourcis sont regroupeacutes en groupe dans un GtkAccelGroup quil faut commencer par creacuteer

raccourciscinclude ltgtkgtkhgtinclude callbackhinclude raccourcish

GtkAccelGroup accel_group_new (gpointer user_data) GtkAccelGroup p_accel_group = NULL

p_accel_group = gtk_accel_group_new () return p_accel_group

Vous commencez agrave avoir lhabitude de cette organisation nous allons donc creacuteer une fonction qui va se chargerdajouter un raccourci au groupe

raccourciscstatic void accelerator_new (GtkAccelGroup p_accel_group const gchar accelerator const gchar accel_path GCallback callback gpointer user_data) guint key GdkModifierType mods GClosure closure = NULL

gtk_accelerator_parse (accelerator ampkey ampmods) closure = g_cclosure_new (callback user_data NULL) gtk_accel_group_connect (p_accel_group key mods GTK_ACCEL_VISIBLE closure) gtk_accel_map_add_entry (accel_path key mods)

La fonction gtk_accelerator_parse permet de deacutecomposer une chaicircne de caractegraveres de la forme ltControlgtF1 ouencore ltAltgtA en numeacutero de touche et modificateur

En plus des touches pour creacuteer un raccourci clavier nous avons besoin dune fonction agrave appeler lorsque lutilisateurappuie sur les touches speacutecifieacutees gtk_accel_group_connect attend une fonction du type GClosure regardons ladocumentation de gobject pour savoir agrave quoi cela correspond

typedef struct

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 13 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IV - Comment afficher plusieurs widgets

IV-A - Aperccedilu

IV-B - Le problegraveme

Dans la partie preacuteceacutedente nous avons reacuteussi agrave afficher un bouton dans la fenecirctre de notre application Si vous avezessayeacute dajouter un second widget GTK+ agrave ducirc vous reacutepondre poliment

(gtk_boxexe492) Gtk-WARNING Attempting to add a widget with typeGtkButton to a GtkWindow but as a GtkBin subclass a GtkWindow can only containone widget at a time it already contains a widget of type GtkButton

Les plus anglophiles dentre vous auront compris que GTK+ naccepte pas lajout un second widget dans notre fenecirctretout simplement parce quil y en a deacutejagrave un et que la sous classe GtkBin (classe megravere de notre GtkWindow) ne peutcontenir quun seul widget

IV-C - La solutions

Pour contourner ce problegraveme il faut commencer par creacuteer un widget qui accepte den contenir plusieurs autrespour ensuite y ajouter tout ce dont nous avons besoin Pour linstant nous utiliserons quun seul widget (il existetrois classes qui permettent ceci) il sagit des GtkBox Il sagit de la meacutethode que jutilise le plus souvent Ce nestpeut-ecirctre pas la plus simple agrave maicirctriser mais elle extrecircmement souple et puissante Elle consiste agrave creacuteer une boicirctepuis agrave y ajouter les widgets les uns apregraves les autres (soit au deacutebut soit agrave la fin) Il existe deux classes heacuteritant deGtkBox les GtkVBox qui empilent les widgets dans le sens vertical et les GtkHBox qui font de mecircme mais dansle sens horizontal Les fonctions pour manipuler ces deux classes sont les mecircmes seule la fonction pour les creacuteerportent un nom diffeacuterent

GtkWidget gtk_vbox_new (gboolean homogeneous gint spacing)GtkWidget gtk_hbox_new (gboolean homogeneous gint spacing)

Le paramegravetre homogeneous permet de reacuteserver pour chaque widget une zone de taille identique (zone que le widgetnest pas obligeacute de remplir) et spacing permet dajouter une bordure en pixels (espacement autour de la GtkBox)Ensuite il suffit dajouter les diffeacuterents widgets gracircce aux fonctions

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)

Qui ajoutent reacuteciproquement le widget child au deacutebut et agrave la fin de box Le paramegravetre expand permet au widget davoirle plus de place possible (si le paramegravetre homogeneous vaut TRUE cette option a aucun effet) Si plusieurs widgetont ce paramegravetre agrave TRUE ils se partagent de faccedilon eacutegale lespace Loption fill permet au widget de remplir toutlespace qui lui ait reacuteserveacute

Pour reacuteellement comprendre linfluence de ces paramegravetres il faut faire des tests en modifiant un agrave un chaqueparamegravetre et observer les effets dun redimentionnement de la fenecirctre principale

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 14 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Le plus gecircnant avec cette meacutethode cest quil faut jongler entre les GtkHBox et les GtkVBox en les imbriquant pourobtenir le reacutesultat souhaiter nheacutesitez pas agrave utiliser une feuille et un crayon )

Pour en revenir agrave notre eacutediteur de texte nous allons preacuteparer notre application agrave contenir les futurs widgetsNous utilisons un GtkVBox pour lensemble des widgets (il sagit de la boicircte principale qui pourra contenir dautresGtkContainer selon nos besoins)

maincinclude ltstdlibhgtinclude ltgtkgtkhgtinclude callbackh

int main (int argc char argv) GtkWidget p_window = NULL GtkWidget p_main_box = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (cb_quit) NULL)

Creation du conteneur principal p_main_box = gtk_vbox_new (FALSE 0) gtk_container_add (GTK_CONTAINER (p_window) p_main_box)

Creation du bouton Quitter GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_QUIT) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_quit) NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_button FALSE FALSE 0)

Affichage de la fenetre principale gtk_widget_show_all (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

IV-D - Code source

chapitre4zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 15 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

V - Afficher le contenue dun fichier

V-A - Aperccedilu

Cliquez pour agrandir

V-B - Saisir du texte

Les choses seacuterieuses vont commencer il sagit de mettre en place le widget qui va nous permettre dafficher etdeacutediter du texte Il sagit de la classe GtkTextView Gracircce agrave GTK+ la mise en place est toujours aussi simple

mainc GtkWidget p_text_view = NULL Creation de la zone de texte p_text_view = gtk_text_view_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_text_view TRUE TRUE 0)

Comme il sagit de la partie centrale de notre application nous demandons agrave ce quelle prenne le plus de placepossible (gracircce agrave la fonction gtk_box_pack_start)

Puisque nous voulons afficher les boutons en dessous de la zone de texte il faut ajouter ce morceau de code avantcelui creacuteant le bouton

V-C - Ouvrir un fichier

Maintenant nous avons une belle zone de texte il faut la remplir avec le contenu dun fichier Pour ce faire nousallons commencer par ajouter un bouton ouvrir

mainc Creation du bouton Ouvrir GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_OPEN) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_open) p_text_view) gtk_box_pack_start (GTK_BOX (p_main_box) p_button FALSE FALSE 0)

Si vous exeacutecutez le programme maintenant (3) vous remarquerez que les boutons sont ajouteacutes les uns en dessousdes autres ce qui diminue la zone de saisie (avec deux boutons ce nest pas gecircnant mais au bout dune dizaineccedila risque decirctre probleacutematique) Pour pallier ce problegraveme nous allons utiliser un nouveau style de GtkBox lesGtkButtonBox qui sont preacutevus pour contenir des boutons (ccedila tombe plutocirct bien D) Donc pour eacuteviter de diminuerla zone de saisie et comme nous avons de la place en largueur nous allons utiliser un GtkHButtonBox qui va ecirctreinclus dans la p_main_box Voici les modifications agrave effectuer

mainc GtkWidget p_button_box = NULL Creation du conteneur pour les boutons p_button_box = gtk_hbutton_box_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_button_box FALSE FALSE 0)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 16 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc gtk_box_pack_start (GTK_BOX (p_button_box) p_button FALSE FALSE 0) gtk_box_pack_start (GTK_BOX (p_button_box) p_button FALSE FALSE 0)

Maintenant il nous reste plus quagrave creacuteer la fonction cb_open dans le fichier callbackc pour linstant nous nouscontenterons douvrir toujours le mecircme fichier nous verrons plus tard comment laisser le choix agrave lutilisateur

callbackcdefine DEFAULT_FILE mainc

void cb_open (GtkWidget p_widget gpointer user_data) open_file (DEFAULT_FILE GTK_TEXT_VIEW (user_data))

Parametre inutilise (void)p_widget

Vous aurez compris que lon va deacuteleacuteguer tout le travail agrave la fonction open_file qui devra ouvrir le fichier dont le nomest passeacute en premier paramegravetre pour lafficher dans le GktTextView

Jai fait ce choix pour deux raisons le code dune fonction callback peut ecirctre tregraves conseacutequent (surtout si lon souhaitequelle affiche une boicircte de dialogue) et aussi parce que cb_open nest peut ecirctre pas la seule fonction agrave copierun fichier dans un GtkTextView (par exemple lors de la creacuteation dun nouveau fichier lon peut vouloir copier unsquelette de fichier)

Pour copier notre fichier plutocirct que dutiliser la fonction fgets nous allons nous servir de la glib (4) qui proposela fonction

gboolean g_file_get_contents (const gchar filename gchar contents gsize length GError error)

Qui nous renvoit le contenu du fichier nommeacute filename dans le tampon contents Il est possible de reacutecupeacuterer lenombre de caractegraveres copieacutes et retourne TRUE en cas de succegraves sinon FALSE et dans ce cas une structure de typeGError est creacutee pour en savoir plus sur le type derreur rencontreacute

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView else print_warning (Impossible douvrir le fichier sn file_name)

Je pense quun certain nombre dexplications simpose (surtout si je vais trop vite nheacutesitez pas agrave marrecircter )

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 17 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

bull g_return_if_fail est une macro qui peut ecirctre compareacutee agrave assert sauf quelle se contente de sortir de la fonctionsi lexpression passeacutee en paramegravetre est fausse Cest une meacutethode pratique pour veacuterifier la validiteacute desparamegravetres (si la fonction doit retourne une valeur utiliseacute plutocirct g_return_val_if_fail qui prend un secondparamegravetre la valeur agrave retourner)

bull Ensuite on essaie de reacutecupeacuterer le contenu de notre fichier

bull Si cela eacutechoue nous le signalons agrave lutilisateur agrave laide de la fonction print_warning

bull Le type gchar est une redeacutefinition du type char par la glib (il en va de mecircme pour tous les autres types du C)privileacutegiez ces types lorsque vous utilisez des fonctions de cette bibliothegraveques

Mais quest-ce donc cette fonction print_warning Cest une fonction que nous allons creacuteer semblable agrave printf quisignalera agrave lutilisateur quune erreur non critique est survenue Comme nous navons pas encore abordeacute les boicirctesde dialogue pour afficher un message il sagira pour linstant dune simple redeacutefinition de printf Pendant que noussommes dans laffichage des messages nous allons aussi creacuteer deux fonctions print_info et print_error qui vontrespectivement afficher un message dinformation et un message derreur critique (ce qui entraicircne la terminaison duprogramme) tout ceci dans un nouveau fichier errorc

errorhifndef H_ERRORdefine H_ERROR

void print_info (char )void print_warning (char )void print_error (char )

endif not H_ERROR

errorcinclude ltstdarghgtinclude ltstdiohgtinclude ltstdlibhgtinclude errorh

void print_info (char format ) va_list va

va_start (va format) printf (Information ) vprintf (format va) printf (n)

void print_warning (char format ) va_list va

va_start (va format) fprintf (stderr Erreur ) vfprintf (stderr format va) fprintf (stderr n)

void print_error (char format ) va_list va

va_start (va format) fprintf (stderr Erreur fatale ) vfprintf (stderr format va) fprintf (stderr n) exit (EXIT_FAILURE)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 18 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

Pour en finir avec louverture dun fichier il nous reste agrave copier contents dans le GtkTextView En fait le GtkTextViewne gegravere que la forme pour modifier le contenu il faut passer par les GtkTextBuffer Commenccedilons donc par reacutecupeacutererce fameux GtkTextBuffer

callbackc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (p_text_view)

Et pour finir on utilise la fonction

void gtk_text_buffer_insert (GtkTextBuffer buffer GtkTextIter iter const gchar text gint len)

Reacutecapitulons buffer est le GtkTextBuffer que lon vient de reacutecupeacuterer text cest le texte agrave afficher et len la taille dece dernier (ou -1 sil sagit dune chaicircne de caractegraveres au sens du langage C)

Mais quest-ce donc ce GtkTextIter On peut voir cela comme un curseur virtuel qui indique la position agrave laquelleeffectuer linsertion de texte dans le GtkTextBuffer (5) Allons voir ce que la documentation peut nous apprendreagrave leur sujet (6)

typedef struct GtkTextIter is an opaque datatype ignore all these fields Initialize the iter with gtk_text_buffer_get_iter_ functions GtkTextIter

Voilagrave on a notre solution suffit de rechercher les fonctions commenccedilant par gtk_text_buffer_get_iter_ voici la liste

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)

La fonction gtk_text_buffer_get_iter_at_line fait parfaitement laffaire

callbackc GtkTextIter iter

gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1)

Cependant si vous ne voulez pas avoir de problegravemes avec le codage des caractegraveres il vaut mieux convertir le codagelocal vers utf8 Voici le reacutesultat final

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 19 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gchar utf8 = NULL GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_text_buffer_insert (p_text_buffer ampiter utf8 -1) g_free (utf8) utf8 = NULL

V-D - La petite touche finale

Pour finir cette laborieuse partie sur une petite touche estheacutetique nous allons demander agrave GTK+ de nous lancerlapplication en plein eacutecran Pour se faire il suffit dajouter lors de la creacuteation de la fenecirctre principale

maincgtk_window_maximize (GTK_WINDOW (p_window))

On peut mecircme se permettre une pointe dexcentriciteacute en modifiant le titre de notre fenecirctre

maincgtk_window_set_title (GTK_WINDOW (p_window) Editeur de texte en GTK+)

V-E - Code source

chapitre5zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 20 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VI - Choisir un fichier

VI-A - Aperccedilu

Cliquez pour agrandir

VI-B - Utilisation dun GtkFileChooserFile

Jusquagrave preacutesent lutilisateur navait pas le choix quant au fichier agrave ouvrir heureusement GTK+ vient agrave notre aide gracircceau widget GtkFileChooserFile qui est tout simplement une boicircte de dialogue qui propose agrave lutilisateur de seacutelectionnerun fichier dans son arborescence disque

Commenccedilons par creacuteer notre boicircte de dialogue dans la fonction cb_open

callbackcvoid cb_open (GtkWidget p_widget gpointer user_data) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Ouvrir un fichier NULL GTK_FILE_CHOOSER_ACTION_OPEN GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_OPEN GTK_RESPONSE_ACCEPT NULL)

Cette fonction neacutecessite le titre de la boicircte de dialogue une fenecirctre parente le type daction (ici on souhaite ouvrir unfichier GTK+ autorisera lutilisateur agrave seacutelectionner uniquement les fichiers existants) Pour finir il sagit dun couple devaleurs GTK_STOCK_ITEMGTK_STOCK_RESPONSE qui permet de creacuteer un bouton utilisant le stock ID speacutecifieacuteet lorsque celui-ci est cliqueacute la fonction servant agrave lancer la boicircte de dialogue retournera le reacuteponse ID correspondantIl existe une seacuterie de valeurs deacutefinies par GTK+ quil est conseilleacute dutiliser

typedef enum GTK returns this if a response widget has no response_id or if the dialog gets programmatically hidden or destroyed GTK_RESPONSE_NONE = -1

GTK wont return these unless you pass them in as the response for an action widget They are for your convenience GTK_RESPONSE_REJECT = -2 GTK_RESPONSE_ACCEPT = -3

If the dialog is deleted GTK_RESPONSE_DELETE_EVENT = -4

These are returned from GTK dialogs and you can also use them yourself if you like GTK_RESPONSE_OK = -5 GTK_RESPONSE_CANCEL = -6 GTK_RESPONSE_CLOSE = -7 GTK_RESPONSE_YES = -8

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 21 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GTK_RESPONSE_NO = -9 GTK_RESPONSE_APPLY = -10 GTK_RESPONSE_HELP = -11 GtkResponseType

Nous indiquons la fin des couples stock idreacuteponse id avec la valeur NULL

Une fois la boicircte de dialogue creacuteee on demande agrave GTK+ de lafficher gracircce agrave la fonction gtk_dialog_run puis onreacutecupegravere sa valeur de retour qui correspond au bouton cliqueacute par lutilisateur

callbackc if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

Ici ce qui nous inteacuteresse cest lorsque que lutilisateur clique sur le bouton ouvrir (donc gtk_dialog_run renvoieGTK_RESPONSE_ACCEPT) dans ce cas il nous suffit de reacutecupeacuterer le nom du fichier seacutelectionneacute puis de louvrir

callbackc gchar file_name = NULL

file_name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) open_file (file_name GTK_TEXT_VIEW (user_data)) g_free (file_name) file_name = NULL

Pour finir dans tous les cas on noublie pas de deacutetruire la boicircte de dialogue

callbackc gtk_widget_destroy (p_dialog)

Et voilagrave le travail lutilisateur peut ouvrir le fichier quil souhaite

VI-C - Code source

chapitre6zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 22 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VII - Interlude

Avant daller plus loin dans lameacutelioration de linterface de notre eacutediteur il est neacutecessaire de modifier sonfonctionnement interne (ne vous inquieacutetez je nai pas dit chambouler) en effet souvenez-vous dans lintroduction jaieacutevoqueacute la possibiliteacutes douvrir plusieurs documents gracircce agrave un systegraveme donglets Pour cela il faut sauvegarder lesproprieacuteteacutes de chaque document ouvert Pris agrave temps ce genre de modification nest pas trop lourde mais si nousattendons cela risque de devenir un vrai casse tecircte

Pour cela nous allons utiliser une structure de donneacutee pour chaque document ouvert qui devra garder en meacutemoirele chemin complet du fichier (ou NULL si le document nest pas encore sauvegarder) sil agrave eacutetait modifier depuis laderniegravere sauvegarde et le GtkTextView qui sert agrave son affichage Voici donc la structure qui va nous servir

documenthtypedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

Sachant que nous serons ameneacute agrave stocker plusieurs occurrences de cette structure il serait bon de reacutefleacutechir degravesmaintenant agrave la structure de donneacutee agrave utiliser pour les stocker La premiegravere ideacutee qui vient agrave lesprit est un tableaualloueacute dynamiquement cependant lutilisateur peut souhaiter fermer un document qui se trouve au milieu on estalors obligeacute de deacutecaler toutes les cellules en amont Dans ce cas il parait naturel dutiliser une liste chaicircneacutee Parchance la glib propose une bibliothegraveque de gestion des listes chaicircneacutees cela nous fera gagner du temps le momentvenu Pour linstant on se contente de creacuteer une structure de donneacutees qui contiendra tous les documents ouverts(stockeacutee dans une GList) et un pointeur sur le document actif (actuellement comme nous navons quun documentouvert en mecircme temps on manipulera uniquement ce pointeur)

documenthtypedef struct GList tous document_t actif docs_t

Maintenant se pose le problegraveme de savoir comment transmettre cette structure On pourrait se servir du paramegravetreuser_data preacutesent dans toutes les fonctions callback mais certaines fonctions utilise deacutejagrave ce paramegravetre (la fonctioncb_open par exemple) il faudrait creacuteer un champs suppleacutementaire dans notre structure documents_s Une solutionplus simple est de creacuteer une variable globale agrave lensemble du programme Ceux qui passe reacuteguliegraverement sur le forumC savent que cest fortement deacuteconseilleacute mais ici nous nous trouvons dans lune des rares exceptions agrave la regravegle Detoute faccedilon cela revient au mecircme que de passer ladresse de notre structure agrave toutes les fonctions callback Nousdeacutefinissons donc un nouveau fichier den-tecircte

documenthifndef H_DOCUMENTdefine H_DOCUMENT

include ltgtkgtkhgt

typedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 23 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

documenthtypedef struct GList tous document_t actif docs_t

extern docs_t docs

endif not H_DOCUMENT

Et dans le fichier mainc

maincinclude documenth

docs_t docs = NULL NULL

Pour linstant la seule fonction qui modifie leacutetat dun document est la fonction open_file il faut donc inclure documenthdans callbackc et modifier leacutegegraverement la fonction pour enregistrer le document ouvert

callbackc if (g_file_get_contents (file_name ampcontents NULL NULL)) Pour linstant il faut allouer la memoire par la suite on modifira simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = g_strdup (file_name) Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = p_text_view Le document vient detre ouvert il nest donc pas modifie docsactif-gtsauve = TRUE

Ne soyez pas choqueacute si je ne teste pas le retour de la fonction g_malloc pour veacuterifier quilnest pas NULL En effet cette derniegravere met fin agrave lapplication si lallocation eacutechoue

VII-A - Code source

chapitre7zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 24 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VIII - Sauvegarder les modification

VIII-A - Aperccedilu

Cliquez pour agrandir

VIII-B - Enregistrer

Avant de pouvoir sauvegarder un document il faut quil soit modifieacute Comment savoir que le contenu du fichier a eacuteteacutemodifier Gracircce au signal changed du GtkTextBuffer que nous interceptons gracircce agrave la fonction cb_modifie

mainc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (p_text_view)) g_signal_connect (G_OBJECT (p_text_buffer) changed G_CALLBACK (cb_modifie) NULL)

Cette derniegravere modifie simplement le champ sauve du document

callbackcvoid cb_modifie (GtkWidget p_widget gpointer user_data) if (docsactif) docsactif-gtsauve = FALSE

Pour la sauvegarde il faut distinguer deux cas soit il sagit de la premiegravere sauvegarde du fichier il faut alors demanderle nom du fichier agrave lutilisateur (cela ressemble fortement agrave louverture dun fichier) soit le fichier est deacutejagrave preacutesent surle disque il suffit de remplacer son contenu par celui du GtkTextViewer Nous avons convenu quun fichier qui neacutetaitpas encore enregistreacute avait sa proprieacuteteacute chemin agrave NULL

Bien sucircr cela na lieu que si un fichier est ouvert et quil a eacuteteacute modifieacute depuis sa derniegravere sauvegarde

callbackcvoid cb_save (GtkWidget p_widget gpointer user_data) if (docsactif) if (docsactif-gtsauve) Le fichier na pas encore ete enregistre if (docsactif-gtchemin) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Sauvegarder le fichier NULL GTK_FILE_CHOOSER_ACTION_SAVE GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_SAVE GTK_RESPONSE_ACCEPT NULL) if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 25 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc docsactif-gtchemin = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) gtk_widget_destroy (p_dialog) Soit le fichier a deja ete enregistre soit lutilisateur vient de nous fournir son nouvel enplacement on peut donc lenregistrer if (docsactif-gtchemin) else print_warning (Aucun document ouvert)

Il nous reste plus quagrave reacutecupeacuterer le contenu du GtkTextViewer et le copier dans le fichier chemin sans oublier dereconvertir le texte dans le codage local

callbackc FILE fichier = NULL

fichier = fopen (docsactif-gtchemin w) if (fichier) gchar contents = NULL gchar locale = NULL GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) contents = gtk_text_buffer_get_text (p_text_buffer ampstart ampend FALSE) locale = g_locale_from_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL fprintf (fichier s locale) g_free (locale) locale = NULL fclose (fichier) fichier = NULL docsactif-gtsauve = TRUE else print_warning (Impossible de sauvegarder le fichier s docsactif-gtchemin)

Le dernier paramegravetre de la fonction gtk_text_buffer_get_text est mis agrave FALSE car nous ne voulons pas enregistrerles caractegraveres invisibles preacutesent dans le GtkTextBuffer Ces caractegraveres servent agrave mettre en forme le texte (taillecouleur) nous pourrions creacuteer un nouveau format de fichier pour enregistrer la mise en forme

VIII-C - Enregistrer sous

Pour enregistrer notre document sous un autre nom il suffit de faire croire agrave cb_save que le document na pas encoreeacutetait enregistreacute tout simplement en changeant chemin agrave NULL et sauve agrave FALSE

callbackcvoid cb_saveas (GtkWidget p_widget gpointer user_data)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 26 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (docsactif) document_t tmp = docsactif

docsactif-gtchemin = NULL docsactif-gtsauve = FALSE cb_save (p_widget user_data) if (docsactif-gtsauve) (docsactif) = tmp else print_warning (Aucun document ouvert)

Il ne faut pas oublier que lutilisateur peut annuler lenregistrement de ce fait nous sauvegardons leacutetat du documentet si la sauvegarde na pas eu lieu on le restaure

VIII-D - Code source

chapitre8zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 27 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IX - Creacuteer un nouveau document

IX-A - Aperccedilu

Cliquez pour agrandir

IX-B - Nouveau fichier

Maintenant que lutilisateur peut ouvrir et fermer un fichier il est inteacuteressant de lui donner la possibiliteacute den creacuteerun nouveau Je ne reviens pas sur la creacuteation du bouton (ccedila devrait deacutejagrave ecirctre fait D) passons directement agrave lafonction cb_new

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) Pour linstant il faut allouer la memoire par la suite on modifiera simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = NULL Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = GTK_TEXT_VIEW (user_data) Le document vient detre creer il nest donc pas modifie docsactif-gtsauve = TRUE gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Je ne sais pas vous mais pour ma part jai fait un copiercoller de la fonction open_file Et oui ouvrir un document peutse reacutesumer agrave creacuteer un document vide puis remplir le GtkTextView avec le fichier souhaiteacute On peut donc simplifiernotre fonction open_file ainsi

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

cb_new (NULL p_text_view) gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE) p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1) Nous sommes obliges de remetre sauve a TRUE car linsertion du contenu du fichier dans le GtkTextView a appele cb_modfie docsactif-gtsauve = TRUE else print_warning (Impossible douvrir le fichier sn file_name)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 28 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc

Cest beau la factorisation du code Par contre nous sommes obligeacutes de remettre sauve agrave TRUE car nous avonsmodifieacute le GtkTextBuffer

IX-C - Code source

chapitre9zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 29 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

X - Fermer

X-A - Aperccedilu

Cliquez pour agrandir

X-B - Fermer un fichier

Maintenant que nous allouons de la meacutemoire il faut la libeacuterer agrave un endroit Logiquement cela va ecirctre fait agrave la fermeturedu document en guise dexercice je vous laisse creacuteer le bouton dans notre boicircte agrave bouton

Allez je vous aide le stock id correspondant est GTK_STOCK_CLOSE

Voilagrave maintenant si tout cest bien passeacute vous devriez ecirctre arriveacute dans le fichier callbackc avec quelque choseressemblant agrave

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data)

Lorsque lon ferme un document il faut vider le GtkTextView (avec les onglets on se contentera de le supprimer)pour cela il faut reacutecupeacuterer le deacutebut et la fin du GtkTextBuffer et demander agrave GTK+ de supprimer tout ce qui ce trouveentre les deux iteacuterateurs

callbackc Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) gtk_text_buffer_delete (p_text_buffer ampstart ampend) else print_warning (Aucun document ouvert)

Bien sucircr il ne faut pas oublier de libeacuterer la meacutemoire

callbackc g_free (docsactif-gtchemin) docsactif-gtchemin = NULL docsactif-gtp_text_view = NULL g_free (docsactif) docsactif = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 30 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour symboliser la fermeture dun document nous deacutesactivons le GtkTextView lors de la fermeture (ne pas oublierde le faire aussi dans mainc)

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) FALSE)

Et nous le reacuteactivons lors de louverture si celle si reacuteussie

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Lorsque lutilisateur quitte lapplication il faut bien sucircr fermer le document sil y en a un ouvert

void cb_quit (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data) gtk_main_quit()

Et aussi lorsquil creacuteeacute un nouveau document (et par conseacutequent lorsquil ouvre un fichier puisque lon fait appel agravecb_new)

void cb_new (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data)

X-C - Enregistrer avant de fermer

Si le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde geacuteneacuteralement le programme le signale agrave lutilisateur etlui propose de sauvegarder ou dannuler la fermeture Pour se faire nous devons modifier la fonction cb_close avantde fermer le document nous allons afficher une boicircte de dialogue

Pour creacuteer une boicircte de dialogue simplement il existe la classe GtkDialog et comme nous avons besoin de boutons(pour que lutilisateur fasse son choix) nous allons creacuteer notre boicircte avec la fonction

GtkWidget gtk_dialog_new_with_buttons (const gchar title GtkWindow parent GtkDialogFlags flags const gchar first_button_text )

Nous retrouvons les mecircmes options que pour le GtkFileChooserDialog mis agrave part option du type GtkDialogFlags

typedef enum GTK_DIALOG_MODAL = 1 ltlt 0 appel gtk_window_set_modal (win TRUE) GTK_DIALOG_DESTROY_WITH_PARENT = 1 ltlt 1 appel gtk_window_set_destroy_with_parent () GTK_DIALOG_NO_SEPARATOR = 1 ltlt 2 Pas de barre de separation au dessus des boutons GtkDialogFlags

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 31 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Nous nous contenterons de rendre notre fenecirctre modale (7)

Pour avoir accegraves agrave notre fenecirctre principale nous ajoutons un champs p_main_window agrave notre structure globaledocs_t que nous initialisons dans la fonction main

mainc docsp_main_window = GTK_WINDOW (p_window)

Il nous reste plus qua creacuteer notre boicircte de dialogue avec trois boutons Oui Non Annuler

callbackc if (docsactif-gtsauve) GtkWidget p_dialog = NULL

p_dialog = gtk_dialog_new_with_buttons (Sauvegarder docsp_main_window GTK_DIALOG_MODAL GTK_STOCK_YES GTK_RESPONSE_YES GTK_STOCK_NO GTK_RESPONSE_NO GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL NULL)

Nous obtenons donc une structure de type GtkDialog

typedef struct GtkWidget vbox GtkWidget action_area GtkDialog

Nous remarquons que cette structure contient deux membres qui permettent dacceacuteder agrave une GtkBox ougrave nous allonsajouter le contenu de la fenecirctre et agrave la partie contenant les boutons

Ensuite la construction de la fenecirctre est identique agrave celle de la fenecirctre principale ici nous nous contenterons dajouterun GtkLabel

callbackc GtkWidget p_label = NULL p_label = gtk_label_new (Voulez-vous sauvegarder les modifications ) gtk_box_pack_start (GTK_BOX (GTK_DIALOG (p_dialog)-gtvbox) p_label TRUE TRUE 0)

Une fois notre fenecirctre precircte il suffit de faire appel agrave la fonction gtk_dialog_run qui va afficher notre GtkDialog et nousretourner le reacuteponse id correspondant au bouton cliqueacute par lutilisateur

callbackc switch (gtk_dialog_run (GTK_DIALOG (p_dialog))) case GTK_RESPONSE_YES cb_save (p_widget user_data) break case GTK_RESPONSE_NO break case GTK_RESPONSE_CANCEL gtk_widget_destroy (p_dialog) return break

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 32 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc gtk_widget_destroy (p_dialog)

Si lutilisateur clique sur non on ne fait rien (le document sera simplement fermeacute) sur oui on enregistre avant defermer et pour finir sil annule on quitte la fonction

X-D - Code source

chapitre10zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 33 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XI - Les barres de deacutefilement

XI-A - Aperccedilu

Cliquez pour agrandir

XI-B - Ajouter des barres de deacutefilement

Apregraves le dernier chapitre quelque peu laborieux voici une partie plus simple mais qui va rendre notre applicationplus pratique En effet si vous avez essayeacute douvrir un fichier de grande taille vous avez pu remarquer que pourpouvoir lire la fin du fichier il fallait utiliser les touches du clavier pas tregraves convivial

Pour rendre la navigation plus aiseacutee on utilise des barres de deacutefilement

mainc GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_scrolled_window TRUE TRUE 0)

Creation de la zone de texte gtk_container_add (GTK_CONTAINER (p_scrolled_window) p_text_view)

Le constructeur de notre GtkScrolledWindow prend en argument deux GtkAdjustment qui permettent de deacutefinirdiffeacuterentes proprieacuteteacutes de la barre de deacutefilement (taille dune page la position de deacutepart) nous laissons GTK+ faireen passant NULL

Cest un bon deacutebut mais estheacutetiquement on peut faire mieux mecircme sil nest pas utile davoir une barre de deacutefilementelle est quand mecircme afficheacutee On peut demander agrave GTK+ de les afficher que si cela est neacutecessaire

mainc gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC)

En fait nous avons de la chance car la classe GtkTextView fait partie des widget qui supporte de faccedilon native les barresde deacutefilement Comment le savoir Ce genre de widget possegravede une ou deux proprieacuteteacutes de type GtkAdjustment (unepour la barre verticale lautre pour la barre horizontale) Actuellement seulement trois classes en sont capables lesGtkTextView les GtkTreeView et les GtkLayout

Comment faire pour les autres widgets Il faut passer par une classe adaptateur GtkViewport afin de creacuteer lesGtkAdjustment

XI-C - Code source

chapitre11zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 34 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XII - Les menus

XII-A - Aperccedilu

Cliquez pour agrandir

XII-B - Creacuteation du menu

Pour simplifier nous avons utiliseacute des boutons pour permettre agrave lutilisateur de creacuteer un document ouvrir un fichierMais il est plus courant dutiliser un menu pour afficher ces options GTK+ propose trois maniegraveres de creacuteer un menu

bull GtkItemFactory cette meacutethode est obsolegravete depuis la version 24 de GTK+

bull GtkUIManager cest ce quon appel une usine agrave gaz pour en savoir plus vous pouvez vous reporter aututoriel Utilisation de GtkUIManager

bull GtkMenu cest ce widget que nous allons eacutetudier il permet de creacuteer un menu manuellement (agrave lopposeacute deGtkUIManager)

Un menu selon GTK+ est composeacute de plusieurs eacuteleacutements

bull GtkMenuBar la barre de menu elle-mecircme

bull GtkMenu la partie deacuteroulante qui contient les diffeacuterents eacuteleacutements

bull GtkMenuItem cest sur ce widget que lutilisateur clique pour lancer une action

Pour commencer faisons linventaire de ce que nous avons besoin

bull Un GtkMenuBar qui sert de base au menu

bull Un GtkMenu pour commencer nous nous aurons dun menu Fichier

bull Six GtkMenuItem pour remplacer nos six boutons

Commenccedilons par la creacuteation du menu nous mettons ce code dans un nouveau fichier dont seul la fonction menu_newsera accessible

menucGtkMenuBar menu_new (gpointer user_data) GtkWidget p_menu_bar = NULL

p_menu_bar = gtk_menu_bar_new () return GTK_MENU_BAR (p_menu_bar)

Le paramegravetre user_data nous servira lors de la connexion des callbacks (nous en avons besoin pour les fonctionscb_new et cb_open)

Ensuite nous allons creacuteer notre sous menu Fichier

menuc Menu Fichier

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 35 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

menuc GtkWidget p_menu = NULL GtkWidget p_menu_item = NULL

p_menu = gtk_menu_new () p_menu_item = gtk_menu_item_new_with_mnemonic (_Fichier) gtk_menu_item_set_submenu (GTK_MENU_ITEM (p_menu_item) p_menu) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu_bar) p_menu_item) return GTK_MENU_BAR (p_menu_bar)

Un sous menu est en fait un GtkMenuItem auquel on assigne un GtkMenu Il faut bien sucircr terminer la creacuteation dusous-menu en lajoutant agrave la barre de menu

Pour finir nous creacuteons les eacuteleacutements du menu les GtkItemMenu Il existe plusieurs types deacuteleacutements (comparableaux diffeacuterents types de bouton) pour commencer nous nutiliserons que le type de base Comme cette opeacuteration estreacutepeacutetitive nous allons creacuteer une fonction pour le faire

menucstatic void menu_item_new (GtkMenu p_menu const gchar title GCallback callback gpointer user_data) GtkWidget p_menu_item = NULL

p_menu_item = gtk_menu_item_new_with_mnemonic (title) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu) p_menu_item) g_signal_connect (G_OBJECT (p_menu_item) activate callback user_data)

Pour permettre agrave lutilisateur dacceacuteder aux diffeacuterents eacuteleacutements du menu agrave laide de la touche ltAltgt nous utilisonsdes mneacutemoniques par exemple pour quitter leacutediteur il suffit de faite Alt+F puis Q Et voici le code pour creacuteer nossix eacuteleacutements du menu

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau G_CALLBACK (cb_new) user_data) menu_item_new (GTK_MENU (p_menu) _Ouvrir G_CALLBACK (cb_open) user_data) menu_item_new (GTK_MENU (p_menu) _Enregistrer G_CALLBACK (cb_save) user_data) menu_item_new (GTK_MENU (p_menu) Enregistrer _sous G_CALLBACK (cb_saveas) user_data) menu_item_new (GTK_MENU (p_menu) _Fermer G_CALLBACK (cb_close) user_data) menu_item_new (GTK_MENU (p_menu) _Quitter G_CALLBACK (cb_quit) user_data)

Voilagrave notre menu est creacuteeacute il nous reste plus quagrave linteacutegrer agrave notre fenecirctre

mainc gtk_box_pack_start (GTK_BOX (p_main_box) GTK_WIDGET (menu_new (p_text_view)) FALSE FALSE 0)

Le problegraveme cest que nous avons besoin de passer le GtkTextView lors de la creacuteation du menu (qui est utiliseacute par lesfonctions cb_new et cb_open) or celui-ci est creacuteeacute apregraves le menu (puisque nous creacuteons les widgets dans lordre ougrave ilfaut les inteacutegrer agrave linterface (8) ) nous devons creacuteer le GtkTextView (seul lappel agrave gtk_text_view_new est deacuteplaceacute)

XII-C - Code source

chapitre12zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 36 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIII - Les barres doutils

XIII-A - Aperccedilu

Cliquez pour agrandir

XIII-B - Creacuteation dune barre doutils

La creacuteation dune barre doutils ressemble fort agrave celle dun menu en plus simple puisquil ny a pas de sous menu on creacutee notre barre doutils (gtk_toolbar_new) puis les eacuteleacutements de la barre pour cela on utilise des boutons(gtk_tool_button_new_from_stock) que lon inseacutere dans la barre (gtk_toolbar_insert) Pas conseacutequent notre fichierbarreoutilsc ressemble agrave menuc

barreoutilscinclude ltgtkgtkhgtinclude callbackhinclude barreoutilsh

static void toolbar_item_new (GtkToolbar const gchar GCallback gpointer)

GtkToolbar toolbar_new (gpointer user_data) GtkWidget p_toolbar = NULL

p_toolbar = gtk_toolbar_new () toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_NEW G_CALLBACK (cb_new) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_OPEN G_CALLBACK (cb_open) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE G_CALLBACK (cb_save) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE_AS G_CALLBACK (cb_saveas) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_CLOSE G_CALLBACK (cb_close) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_QUIT G_CALLBACK (cb_quit) user_data) return GTK_TOOLBAR (p_toolbar)

static void toolbar_item_new (GtkToolbar p_toolbar const gchar stock_id GCallback callback gpointer user_data) GtkToolItem p_tool_item = NULL

p_tool_item = gtk_tool_button_new_from_stock (stock_id) g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data) gtk_toolbar_insert (p_toolbar p_tool_item -1)

Le code nest pas complet car lorsque jexeacutecute le programme GTK+ affiche en plus des icocircnes le texte sous lesboutons Pour modifier cela il suffit dajouter une ligne de code

barreoutilsc gtk_toolbar_set_style (GTK_TOOLBAR (p_toolbar) GTK_TOOLBAR_ICONS)

Pourquoi gtk_tool_button_new_from_stock retourne un GtkToolItem et non un GtkWidgetcomme nous avons eacuteteacute habitueacute jusquagrave preacutesent Il sagit dune bizarrerie de GTK+ dontje ne connais pas la raison

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 37 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour anticiper un changement dinterface (dans GTK+ 30 peut ecirctre ) nous aurions pueacutecrire

Gtkwidget p_tool_item = NULL

p_tool_item = GTK_WIDGET (gtk_tool_button_new_from_stock (stock_id))g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data)gtk_toolbar_insert (p_toolbar GTK_TOOL_ITEM (p_tool_item) -1)

XIII-C - Code source

chapitre13zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 38 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIV - Les racourcis clavier

XIV-A - Aperccedilu

Cliquez pour agrandir

XIV-B - Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mneacutemoniques ces derniers permettent dacceacuteder agrave un eacuteleacutementseacutequentiellement alors que les raccourcis appellent une fonction si lutilisateur appuie simultaneacutement sur une ouplusieurs touches (geacuteneacuteralement de la forme ltModificateurgtTouche ougrave Modificateur repreacutesente les touches ShiftAlt et Control) Ce raccourci peut ecirctre attacheacute agrave un eacuteleacutement du menu mais ceci nest pas obligatoire

Les raccourcis sont regroupeacutes en groupe dans un GtkAccelGroup quil faut commencer par creacuteer

raccourciscinclude ltgtkgtkhgtinclude callbackhinclude raccourcish

GtkAccelGroup accel_group_new (gpointer user_data) GtkAccelGroup p_accel_group = NULL

p_accel_group = gtk_accel_group_new () return p_accel_group

Vous commencez agrave avoir lhabitude de cette organisation nous allons donc creacuteer une fonction qui va se chargerdajouter un raccourci au groupe

raccourciscstatic void accelerator_new (GtkAccelGroup p_accel_group const gchar accelerator const gchar accel_path GCallback callback gpointer user_data) guint key GdkModifierType mods GClosure closure = NULL

gtk_accelerator_parse (accelerator ampkey ampmods) closure = g_cclosure_new (callback user_data NULL) gtk_accel_group_connect (p_accel_group key mods GTK_ACCEL_VISIBLE closure) gtk_accel_map_add_entry (accel_path key mods)

La fonction gtk_accelerator_parse permet de deacutecomposer une chaicircne de caractegraveres de la forme ltControlgtF1 ouencore ltAltgtA en numeacutero de touche et modificateur

En plus des touches pour creacuteer un raccourci clavier nous avons besoin dune fonction agrave appeler lorsque lutilisateurappuie sur les touches speacutecifieacutees gtk_accel_group_connect attend une fonction du type GClosure regardons ladocumentation de gobject pour savoir agrave quoi cela correspond

typedef struct

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 14 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Le plus gecircnant avec cette meacutethode cest quil faut jongler entre les GtkHBox et les GtkVBox en les imbriquant pourobtenir le reacutesultat souhaiter nheacutesitez pas agrave utiliser une feuille et un crayon )

Pour en revenir agrave notre eacutediteur de texte nous allons preacuteparer notre application agrave contenir les futurs widgetsNous utilisons un GtkVBox pour lensemble des widgets (il sagit de la boicircte principale qui pourra contenir dautresGtkContainer selon nos besoins)

maincinclude ltstdlibhgtinclude ltgtkgtkhgtinclude callbackh

int main (int argc char argv) GtkWidget p_window = NULL GtkWidget p_main_box = NULL

Initialisation de GTK+ gtk_init (ampargc ampargv)

Creation de la fenetre principale de notre application p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL) g_signal_connect (G_OBJECT (p_window) destroy G_CALLBACK (cb_quit) NULL)

Creation du conteneur principal p_main_box = gtk_vbox_new (FALSE 0) gtk_container_add (GTK_CONTAINER (p_window) p_main_box)

Creation du bouton Quitter GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_QUIT) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_quit) NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_button FALSE FALSE 0)

Affichage de la fenetre principale gtk_widget_show_all (p_window) Lancement de la boucle principale gtk_main () return EXIT_SUCCESS

IV-D - Code source

chapitre4zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 15 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

V - Afficher le contenue dun fichier

V-A - Aperccedilu

Cliquez pour agrandir

V-B - Saisir du texte

Les choses seacuterieuses vont commencer il sagit de mettre en place le widget qui va nous permettre dafficher etdeacutediter du texte Il sagit de la classe GtkTextView Gracircce agrave GTK+ la mise en place est toujours aussi simple

mainc GtkWidget p_text_view = NULL Creation de la zone de texte p_text_view = gtk_text_view_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_text_view TRUE TRUE 0)

Comme il sagit de la partie centrale de notre application nous demandons agrave ce quelle prenne le plus de placepossible (gracircce agrave la fonction gtk_box_pack_start)

Puisque nous voulons afficher les boutons en dessous de la zone de texte il faut ajouter ce morceau de code avantcelui creacuteant le bouton

V-C - Ouvrir un fichier

Maintenant nous avons une belle zone de texte il faut la remplir avec le contenu dun fichier Pour ce faire nousallons commencer par ajouter un bouton ouvrir

mainc Creation du bouton Ouvrir GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_OPEN) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_open) p_text_view) gtk_box_pack_start (GTK_BOX (p_main_box) p_button FALSE FALSE 0)

Si vous exeacutecutez le programme maintenant (3) vous remarquerez que les boutons sont ajouteacutes les uns en dessousdes autres ce qui diminue la zone de saisie (avec deux boutons ce nest pas gecircnant mais au bout dune dizaineccedila risque decirctre probleacutematique) Pour pallier ce problegraveme nous allons utiliser un nouveau style de GtkBox lesGtkButtonBox qui sont preacutevus pour contenir des boutons (ccedila tombe plutocirct bien D) Donc pour eacuteviter de diminuerla zone de saisie et comme nous avons de la place en largueur nous allons utiliser un GtkHButtonBox qui va ecirctreinclus dans la p_main_box Voici les modifications agrave effectuer

mainc GtkWidget p_button_box = NULL Creation du conteneur pour les boutons p_button_box = gtk_hbutton_box_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_button_box FALSE FALSE 0)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 16 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc gtk_box_pack_start (GTK_BOX (p_button_box) p_button FALSE FALSE 0) gtk_box_pack_start (GTK_BOX (p_button_box) p_button FALSE FALSE 0)

Maintenant il nous reste plus quagrave creacuteer la fonction cb_open dans le fichier callbackc pour linstant nous nouscontenterons douvrir toujours le mecircme fichier nous verrons plus tard comment laisser le choix agrave lutilisateur

callbackcdefine DEFAULT_FILE mainc

void cb_open (GtkWidget p_widget gpointer user_data) open_file (DEFAULT_FILE GTK_TEXT_VIEW (user_data))

Parametre inutilise (void)p_widget

Vous aurez compris que lon va deacuteleacuteguer tout le travail agrave la fonction open_file qui devra ouvrir le fichier dont le nomest passeacute en premier paramegravetre pour lafficher dans le GktTextView

Jai fait ce choix pour deux raisons le code dune fonction callback peut ecirctre tregraves conseacutequent (surtout si lon souhaitequelle affiche une boicircte de dialogue) et aussi parce que cb_open nest peut ecirctre pas la seule fonction agrave copierun fichier dans un GtkTextView (par exemple lors de la creacuteation dun nouveau fichier lon peut vouloir copier unsquelette de fichier)

Pour copier notre fichier plutocirct que dutiliser la fonction fgets nous allons nous servir de la glib (4) qui proposela fonction

gboolean g_file_get_contents (const gchar filename gchar contents gsize length GError error)

Qui nous renvoit le contenu du fichier nommeacute filename dans le tampon contents Il est possible de reacutecupeacuterer lenombre de caractegraveres copieacutes et retourne TRUE en cas de succegraves sinon FALSE et dans ce cas une structure de typeGError est creacutee pour en savoir plus sur le type derreur rencontreacute

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView else print_warning (Impossible douvrir le fichier sn file_name)

Je pense quun certain nombre dexplications simpose (surtout si je vais trop vite nheacutesitez pas agrave marrecircter )

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 17 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

bull g_return_if_fail est une macro qui peut ecirctre compareacutee agrave assert sauf quelle se contente de sortir de la fonctionsi lexpression passeacutee en paramegravetre est fausse Cest une meacutethode pratique pour veacuterifier la validiteacute desparamegravetres (si la fonction doit retourne une valeur utiliseacute plutocirct g_return_val_if_fail qui prend un secondparamegravetre la valeur agrave retourner)

bull Ensuite on essaie de reacutecupeacuterer le contenu de notre fichier

bull Si cela eacutechoue nous le signalons agrave lutilisateur agrave laide de la fonction print_warning

bull Le type gchar est une redeacutefinition du type char par la glib (il en va de mecircme pour tous les autres types du C)privileacutegiez ces types lorsque vous utilisez des fonctions de cette bibliothegraveques

Mais quest-ce donc cette fonction print_warning Cest une fonction que nous allons creacuteer semblable agrave printf quisignalera agrave lutilisateur quune erreur non critique est survenue Comme nous navons pas encore abordeacute les boicirctesde dialogue pour afficher un message il sagira pour linstant dune simple redeacutefinition de printf Pendant que noussommes dans laffichage des messages nous allons aussi creacuteer deux fonctions print_info et print_error qui vontrespectivement afficher un message dinformation et un message derreur critique (ce qui entraicircne la terminaison duprogramme) tout ceci dans un nouveau fichier errorc

errorhifndef H_ERRORdefine H_ERROR

void print_info (char )void print_warning (char )void print_error (char )

endif not H_ERROR

errorcinclude ltstdarghgtinclude ltstdiohgtinclude ltstdlibhgtinclude errorh

void print_info (char format ) va_list va

va_start (va format) printf (Information ) vprintf (format va) printf (n)

void print_warning (char format ) va_list va

va_start (va format) fprintf (stderr Erreur ) vfprintf (stderr format va) fprintf (stderr n)

void print_error (char format ) va_list va

va_start (va format) fprintf (stderr Erreur fatale ) vfprintf (stderr format va) fprintf (stderr n) exit (EXIT_FAILURE)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 18 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

Pour en finir avec louverture dun fichier il nous reste agrave copier contents dans le GtkTextView En fait le GtkTextViewne gegravere que la forme pour modifier le contenu il faut passer par les GtkTextBuffer Commenccedilons donc par reacutecupeacutererce fameux GtkTextBuffer

callbackc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (p_text_view)

Et pour finir on utilise la fonction

void gtk_text_buffer_insert (GtkTextBuffer buffer GtkTextIter iter const gchar text gint len)

Reacutecapitulons buffer est le GtkTextBuffer que lon vient de reacutecupeacuterer text cest le texte agrave afficher et len la taille dece dernier (ou -1 sil sagit dune chaicircne de caractegraveres au sens du langage C)

Mais quest-ce donc ce GtkTextIter On peut voir cela comme un curseur virtuel qui indique la position agrave laquelleeffectuer linsertion de texte dans le GtkTextBuffer (5) Allons voir ce que la documentation peut nous apprendreagrave leur sujet (6)

typedef struct GtkTextIter is an opaque datatype ignore all these fields Initialize the iter with gtk_text_buffer_get_iter_ functions GtkTextIter

Voilagrave on a notre solution suffit de rechercher les fonctions commenccedilant par gtk_text_buffer_get_iter_ voici la liste

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)

La fonction gtk_text_buffer_get_iter_at_line fait parfaitement laffaire

callbackc GtkTextIter iter

gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1)

Cependant si vous ne voulez pas avoir de problegravemes avec le codage des caractegraveres il vaut mieux convertir le codagelocal vers utf8 Voici le reacutesultat final

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 19 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gchar utf8 = NULL GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_text_buffer_insert (p_text_buffer ampiter utf8 -1) g_free (utf8) utf8 = NULL

V-D - La petite touche finale

Pour finir cette laborieuse partie sur une petite touche estheacutetique nous allons demander agrave GTK+ de nous lancerlapplication en plein eacutecran Pour se faire il suffit dajouter lors de la creacuteation de la fenecirctre principale

maincgtk_window_maximize (GTK_WINDOW (p_window))

On peut mecircme se permettre une pointe dexcentriciteacute en modifiant le titre de notre fenecirctre

maincgtk_window_set_title (GTK_WINDOW (p_window) Editeur de texte en GTK+)

V-E - Code source

chapitre5zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 20 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VI - Choisir un fichier

VI-A - Aperccedilu

Cliquez pour agrandir

VI-B - Utilisation dun GtkFileChooserFile

Jusquagrave preacutesent lutilisateur navait pas le choix quant au fichier agrave ouvrir heureusement GTK+ vient agrave notre aide gracircceau widget GtkFileChooserFile qui est tout simplement une boicircte de dialogue qui propose agrave lutilisateur de seacutelectionnerun fichier dans son arborescence disque

Commenccedilons par creacuteer notre boicircte de dialogue dans la fonction cb_open

callbackcvoid cb_open (GtkWidget p_widget gpointer user_data) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Ouvrir un fichier NULL GTK_FILE_CHOOSER_ACTION_OPEN GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_OPEN GTK_RESPONSE_ACCEPT NULL)

Cette fonction neacutecessite le titre de la boicircte de dialogue une fenecirctre parente le type daction (ici on souhaite ouvrir unfichier GTK+ autorisera lutilisateur agrave seacutelectionner uniquement les fichiers existants) Pour finir il sagit dun couple devaleurs GTK_STOCK_ITEMGTK_STOCK_RESPONSE qui permet de creacuteer un bouton utilisant le stock ID speacutecifieacuteet lorsque celui-ci est cliqueacute la fonction servant agrave lancer la boicircte de dialogue retournera le reacuteponse ID correspondantIl existe une seacuterie de valeurs deacutefinies par GTK+ quil est conseilleacute dutiliser

typedef enum GTK returns this if a response widget has no response_id or if the dialog gets programmatically hidden or destroyed GTK_RESPONSE_NONE = -1

GTK wont return these unless you pass them in as the response for an action widget They are for your convenience GTK_RESPONSE_REJECT = -2 GTK_RESPONSE_ACCEPT = -3

If the dialog is deleted GTK_RESPONSE_DELETE_EVENT = -4

These are returned from GTK dialogs and you can also use them yourself if you like GTK_RESPONSE_OK = -5 GTK_RESPONSE_CANCEL = -6 GTK_RESPONSE_CLOSE = -7 GTK_RESPONSE_YES = -8

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 21 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GTK_RESPONSE_NO = -9 GTK_RESPONSE_APPLY = -10 GTK_RESPONSE_HELP = -11 GtkResponseType

Nous indiquons la fin des couples stock idreacuteponse id avec la valeur NULL

Une fois la boicircte de dialogue creacuteee on demande agrave GTK+ de lafficher gracircce agrave la fonction gtk_dialog_run puis onreacutecupegravere sa valeur de retour qui correspond au bouton cliqueacute par lutilisateur

callbackc if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

Ici ce qui nous inteacuteresse cest lorsque que lutilisateur clique sur le bouton ouvrir (donc gtk_dialog_run renvoieGTK_RESPONSE_ACCEPT) dans ce cas il nous suffit de reacutecupeacuterer le nom du fichier seacutelectionneacute puis de louvrir

callbackc gchar file_name = NULL

file_name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) open_file (file_name GTK_TEXT_VIEW (user_data)) g_free (file_name) file_name = NULL

Pour finir dans tous les cas on noublie pas de deacutetruire la boicircte de dialogue

callbackc gtk_widget_destroy (p_dialog)

Et voilagrave le travail lutilisateur peut ouvrir le fichier quil souhaite

VI-C - Code source

chapitre6zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 22 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VII - Interlude

Avant daller plus loin dans lameacutelioration de linterface de notre eacutediteur il est neacutecessaire de modifier sonfonctionnement interne (ne vous inquieacutetez je nai pas dit chambouler) en effet souvenez-vous dans lintroduction jaieacutevoqueacute la possibiliteacutes douvrir plusieurs documents gracircce agrave un systegraveme donglets Pour cela il faut sauvegarder lesproprieacuteteacutes de chaque document ouvert Pris agrave temps ce genre de modification nest pas trop lourde mais si nousattendons cela risque de devenir un vrai casse tecircte

Pour cela nous allons utiliser une structure de donneacutee pour chaque document ouvert qui devra garder en meacutemoirele chemin complet du fichier (ou NULL si le document nest pas encore sauvegarder) sil agrave eacutetait modifier depuis laderniegravere sauvegarde et le GtkTextView qui sert agrave son affichage Voici donc la structure qui va nous servir

documenthtypedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

Sachant que nous serons ameneacute agrave stocker plusieurs occurrences de cette structure il serait bon de reacutefleacutechir degravesmaintenant agrave la structure de donneacutee agrave utiliser pour les stocker La premiegravere ideacutee qui vient agrave lesprit est un tableaualloueacute dynamiquement cependant lutilisateur peut souhaiter fermer un document qui se trouve au milieu on estalors obligeacute de deacutecaler toutes les cellules en amont Dans ce cas il parait naturel dutiliser une liste chaicircneacutee Parchance la glib propose une bibliothegraveque de gestion des listes chaicircneacutees cela nous fera gagner du temps le momentvenu Pour linstant on se contente de creacuteer une structure de donneacutees qui contiendra tous les documents ouverts(stockeacutee dans une GList) et un pointeur sur le document actif (actuellement comme nous navons quun documentouvert en mecircme temps on manipulera uniquement ce pointeur)

documenthtypedef struct GList tous document_t actif docs_t

Maintenant se pose le problegraveme de savoir comment transmettre cette structure On pourrait se servir du paramegravetreuser_data preacutesent dans toutes les fonctions callback mais certaines fonctions utilise deacutejagrave ce paramegravetre (la fonctioncb_open par exemple) il faudrait creacuteer un champs suppleacutementaire dans notre structure documents_s Une solutionplus simple est de creacuteer une variable globale agrave lensemble du programme Ceux qui passe reacuteguliegraverement sur le forumC savent que cest fortement deacuteconseilleacute mais ici nous nous trouvons dans lune des rares exceptions agrave la regravegle Detoute faccedilon cela revient au mecircme que de passer ladresse de notre structure agrave toutes les fonctions callback Nousdeacutefinissons donc un nouveau fichier den-tecircte

documenthifndef H_DOCUMENTdefine H_DOCUMENT

include ltgtkgtkhgt

typedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 23 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

documenthtypedef struct GList tous document_t actif docs_t

extern docs_t docs

endif not H_DOCUMENT

Et dans le fichier mainc

maincinclude documenth

docs_t docs = NULL NULL

Pour linstant la seule fonction qui modifie leacutetat dun document est la fonction open_file il faut donc inclure documenthdans callbackc et modifier leacutegegraverement la fonction pour enregistrer le document ouvert

callbackc if (g_file_get_contents (file_name ampcontents NULL NULL)) Pour linstant il faut allouer la memoire par la suite on modifira simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = g_strdup (file_name) Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = p_text_view Le document vient detre ouvert il nest donc pas modifie docsactif-gtsauve = TRUE

Ne soyez pas choqueacute si je ne teste pas le retour de la fonction g_malloc pour veacuterifier quilnest pas NULL En effet cette derniegravere met fin agrave lapplication si lallocation eacutechoue

VII-A - Code source

chapitre7zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 24 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VIII - Sauvegarder les modification

VIII-A - Aperccedilu

Cliquez pour agrandir

VIII-B - Enregistrer

Avant de pouvoir sauvegarder un document il faut quil soit modifieacute Comment savoir que le contenu du fichier a eacuteteacutemodifier Gracircce au signal changed du GtkTextBuffer que nous interceptons gracircce agrave la fonction cb_modifie

mainc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (p_text_view)) g_signal_connect (G_OBJECT (p_text_buffer) changed G_CALLBACK (cb_modifie) NULL)

Cette derniegravere modifie simplement le champ sauve du document

callbackcvoid cb_modifie (GtkWidget p_widget gpointer user_data) if (docsactif) docsactif-gtsauve = FALSE

Pour la sauvegarde il faut distinguer deux cas soit il sagit de la premiegravere sauvegarde du fichier il faut alors demanderle nom du fichier agrave lutilisateur (cela ressemble fortement agrave louverture dun fichier) soit le fichier est deacutejagrave preacutesent surle disque il suffit de remplacer son contenu par celui du GtkTextViewer Nous avons convenu quun fichier qui neacutetaitpas encore enregistreacute avait sa proprieacuteteacute chemin agrave NULL

Bien sucircr cela na lieu que si un fichier est ouvert et quil a eacuteteacute modifieacute depuis sa derniegravere sauvegarde

callbackcvoid cb_save (GtkWidget p_widget gpointer user_data) if (docsactif) if (docsactif-gtsauve) Le fichier na pas encore ete enregistre if (docsactif-gtchemin) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Sauvegarder le fichier NULL GTK_FILE_CHOOSER_ACTION_SAVE GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_SAVE GTK_RESPONSE_ACCEPT NULL) if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 25 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc docsactif-gtchemin = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) gtk_widget_destroy (p_dialog) Soit le fichier a deja ete enregistre soit lutilisateur vient de nous fournir son nouvel enplacement on peut donc lenregistrer if (docsactif-gtchemin) else print_warning (Aucun document ouvert)

Il nous reste plus quagrave reacutecupeacuterer le contenu du GtkTextViewer et le copier dans le fichier chemin sans oublier dereconvertir le texte dans le codage local

callbackc FILE fichier = NULL

fichier = fopen (docsactif-gtchemin w) if (fichier) gchar contents = NULL gchar locale = NULL GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) contents = gtk_text_buffer_get_text (p_text_buffer ampstart ampend FALSE) locale = g_locale_from_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL fprintf (fichier s locale) g_free (locale) locale = NULL fclose (fichier) fichier = NULL docsactif-gtsauve = TRUE else print_warning (Impossible de sauvegarder le fichier s docsactif-gtchemin)

Le dernier paramegravetre de la fonction gtk_text_buffer_get_text est mis agrave FALSE car nous ne voulons pas enregistrerles caractegraveres invisibles preacutesent dans le GtkTextBuffer Ces caractegraveres servent agrave mettre en forme le texte (taillecouleur) nous pourrions creacuteer un nouveau format de fichier pour enregistrer la mise en forme

VIII-C - Enregistrer sous

Pour enregistrer notre document sous un autre nom il suffit de faire croire agrave cb_save que le document na pas encoreeacutetait enregistreacute tout simplement en changeant chemin agrave NULL et sauve agrave FALSE

callbackcvoid cb_saveas (GtkWidget p_widget gpointer user_data)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 26 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (docsactif) document_t tmp = docsactif

docsactif-gtchemin = NULL docsactif-gtsauve = FALSE cb_save (p_widget user_data) if (docsactif-gtsauve) (docsactif) = tmp else print_warning (Aucun document ouvert)

Il ne faut pas oublier que lutilisateur peut annuler lenregistrement de ce fait nous sauvegardons leacutetat du documentet si la sauvegarde na pas eu lieu on le restaure

VIII-D - Code source

chapitre8zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 27 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IX - Creacuteer un nouveau document

IX-A - Aperccedilu

Cliquez pour agrandir

IX-B - Nouveau fichier

Maintenant que lutilisateur peut ouvrir et fermer un fichier il est inteacuteressant de lui donner la possibiliteacute den creacuteerun nouveau Je ne reviens pas sur la creacuteation du bouton (ccedila devrait deacutejagrave ecirctre fait D) passons directement agrave lafonction cb_new

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) Pour linstant il faut allouer la memoire par la suite on modifiera simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = NULL Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = GTK_TEXT_VIEW (user_data) Le document vient detre creer il nest donc pas modifie docsactif-gtsauve = TRUE gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Je ne sais pas vous mais pour ma part jai fait un copiercoller de la fonction open_file Et oui ouvrir un document peutse reacutesumer agrave creacuteer un document vide puis remplir le GtkTextView avec le fichier souhaiteacute On peut donc simplifiernotre fonction open_file ainsi

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

cb_new (NULL p_text_view) gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE) p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1) Nous sommes obliges de remetre sauve a TRUE car linsertion du contenu du fichier dans le GtkTextView a appele cb_modfie docsactif-gtsauve = TRUE else print_warning (Impossible douvrir le fichier sn file_name)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 28 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc

Cest beau la factorisation du code Par contre nous sommes obligeacutes de remettre sauve agrave TRUE car nous avonsmodifieacute le GtkTextBuffer

IX-C - Code source

chapitre9zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 29 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

X - Fermer

X-A - Aperccedilu

Cliquez pour agrandir

X-B - Fermer un fichier

Maintenant que nous allouons de la meacutemoire il faut la libeacuterer agrave un endroit Logiquement cela va ecirctre fait agrave la fermeturedu document en guise dexercice je vous laisse creacuteer le bouton dans notre boicircte agrave bouton

Allez je vous aide le stock id correspondant est GTK_STOCK_CLOSE

Voilagrave maintenant si tout cest bien passeacute vous devriez ecirctre arriveacute dans le fichier callbackc avec quelque choseressemblant agrave

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data)

Lorsque lon ferme un document il faut vider le GtkTextView (avec les onglets on se contentera de le supprimer)pour cela il faut reacutecupeacuterer le deacutebut et la fin du GtkTextBuffer et demander agrave GTK+ de supprimer tout ce qui ce trouveentre les deux iteacuterateurs

callbackc Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) gtk_text_buffer_delete (p_text_buffer ampstart ampend) else print_warning (Aucun document ouvert)

Bien sucircr il ne faut pas oublier de libeacuterer la meacutemoire

callbackc g_free (docsactif-gtchemin) docsactif-gtchemin = NULL docsactif-gtp_text_view = NULL g_free (docsactif) docsactif = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 30 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour symboliser la fermeture dun document nous deacutesactivons le GtkTextView lors de la fermeture (ne pas oublierde le faire aussi dans mainc)

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) FALSE)

Et nous le reacuteactivons lors de louverture si celle si reacuteussie

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Lorsque lutilisateur quitte lapplication il faut bien sucircr fermer le document sil y en a un ouvert

void cb_quit (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data) gtk_main_quit()

Et aussi lorsquil creacuteeacute un nouveau document (et par conseacutequent lorsquil ouvre un fichier puisque lon fait appel agravecb_new)

void cb_new (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data)

X-C - Enregistrer avant de fermer

Si le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde geacuteneacuteralement le programme le signale agrave lutilisateur etlui propose de sauvegarder ou dannuler la fermeture Pour se faire nous devons modifier la fonction cb_close avantde fermer le document nous allons afficher une boicircte de dialogue

Pour creacuteer une boicircte de dialogue simplement il existe la classe GtkDialog et comme nous avons besoin de boutons(pour que lutilisateur fasse son choix) nous allons creacuteer notre boicircte avec la fonction

GtkWidget gtk_dialog_new_with_buttons (const gchar title GtkWindow parent GtkDialogFlags flags const gchar first_button_text )

Nous retrouvons les mecircmes options que pour le GtkFileChooserDialog mis agrave part option du type GtkDialogFlags

typedef enum GTK_DIALOG_MODAL = 1 ltlt 0 appel gtk_window_set_modal (win TRUE) GTK_DIALOG_DESTROY_WITH_PARENT = 1 ltlt 1 appel gtk_window_set_destroy_with_parent () GTK_DIALOG_NO_SEPARATOR = 1 ltlt 2 Pas de barre de separation au dessus des boutons GtkDialogFlags

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 31 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Nous nous contenterons de rendre notre fenecirctre modale (7)

Pour avoir accegraves agrave notre fenecirctre principale nous ajoutons un champs p_main_window agrave notre structure globaledocs_t que nous initialisons dans la fonction main

mainc docsp_main_window = GTK_WINDOW (p_window)

Il nous reste plus qua creacuteer notre boicircte de dialogue avec trois boutons Oui Non Annuler

callbackc if (docsactif-gtsauve) GtkWidget p_dialog = NULL

p_dialog = gtk_dialog_new_with_buttons (Sauvegarder docsp_main_window GTK_DIALOG_MODAL GTK_STOCK_YES GTK_RESPONSE_YES GTK_STOCK_NO GTK_RESPONSE_NO GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL NULL)

Nous obtenons donc une structure de type GtkDialog

typedef struct GtkWidget vbox GtkWidget action_area GtkDialog

Nous remarquons que cette structure contient deux membres qui permettent dacceacuteder agrave une GtkBox ougrave nous allonsajouter le contenu de la fenecirctre et agrave la partie contenant les boutons

Ensuite la construction de la fenecirctre est identique agrave celle de la fenecirctre principale ici nous nous contenterons dajouterun GtkLabel

callbackc GtkWidget p_label = NULL p_label = gtk_label_new (Voulez-vous sauvegarder les modifications ) gtk_box_pack_start (GTK_BOX (GTK_DIALOG (p_dialog)-gtvbox) p_label TRUE TRUE 0)

Une fois notre fenecirctre precircte il suffit de faire appel agrave la fonction gtk_dialog_run qui va afficher notre GtkDialog et nousretourner le reacuteponse id correspondant au bouton cliqueacute par lutilisateur

callbackc switch (gtk_dialog_run (GTK_DIALOG (p_dialog))) case GTK_RESPONSE_YES cb_save (p_widget user_data) break case GTK_RESPONSE_NO break case GTK_RESPONSE_CANCEL gtk_widget_destroy (p_dialog) return break

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 32 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc gtk_widget_destroy (p_dialog)

Si lutilisateur clique sur non on ne fait rien (le document sera simplement fermeacute) sur oui on enregistre avant defermer et pour finir sil annule on quitte la fonction

X-D - Code source

chapitre10zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 33 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XI - Les barres de deacutefilement

XI-A - Aperccedilu

Cliquez pour agrandir

XI-B - Ajouter des barres de deacutefilement

Apregraves le dernier chapitre quelque peu laborieux voici une partie plus simple mais qui va rendre notre applicationplus pratique En effet si vous avez essayeacute douvrir un fichier de grande taille vous avez pu remarquer que pourpouvoir lire la fin du fichier il fallait utiliser les touches du clavier pas tregraves convivial

Pour rendre la navigation plus aiseacutee on utilise des barres de deacutefilement

mainc GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_scrolled_window TRUE TRUE 0)

Creation de la zone de texte gtk_container_add (GTK_CONTAINER (p_scrolled_window) p_text_view)

Le constructeur de notre GtkScrolledWindow prend en argument deux GtkAdjustment qui permettent de deacutefinirdiffeacuterentes proprieacuteteacutes de la barre de deacutefilement (taille dune page la position de deacutepart) nous laissons GTK+ faireen passant NULL

Cest un bon deacutebut mais estheacutetiquement on peut faire mieux mecircme sil nest pas utile davoir une barre de deacutefilementelle est quand mecircme afficheacutee On peut demander agrave GTK+ de les afficher que si cela est neacutecessaire

mainc gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC)

En fait nous avons de la chance car la classe GtkTextView fait partie des widget qui supporte de faccedilon native les barresde deacutefilement Comment le savoir Ce genre de widget possegravede une ou deux proprieacuteteacutes de type GtkAdjustment (unepour la barre verticale lautre pour la barre horizontale) Actuellement seulement trois classes en sont capables lesGtkTextView les GtkTreeView et les GtkLayout

Comment faire pour les autres widgets Il faut passer par une classe adaptateur GtkViewport afin de creacuteer lesGtkAdjustment

XI-C - Code source

chapitre11zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 34 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XII - Les menus

XII-A - Aperccedilu

Cliquez pour agrandir

XII-B - Creacuteation du menu

Pour simplifier nous avons utiliseacute des boutons pour permettre agrave lutilisateur de creacuteer un document ouvrir un fichierMais il est plus courant dutiliser un menu pour afficher ces options GTK+ propose trois maniegraveres de creacuteer un menu

bull GtkItemFactory cette meacutethode est obsolegravete depuis la version 24 de GTK+

bull GtkUIManager cest ce quon appel une usine agrave gaz pour en savoir plus vous pouvez vous reporter aututoriel Utilisation de GtkUIManager

bull GtkMenu cest ce widget que nous allons eacutetudier il permet de creacuteer un menu manuellement (agrave lopposeacute deGtkUIManager)

Un menu selon GTK+ est composeacute de plusieurs eacuteleacutements

bull GtkMenuBar la barre de menu elle-mecircme

bull GtkMenu la partie deacuteroulante qui contient les diffeacuterents eacuteleacutements

bull GtkMenuItem cest sur ce widget que lutilisateur clique pour lancer une action

Pour commencer faisons linventaire de ce que nous avons besoin

bull Un GtkMenuBar qui sert de base au menu

bull Un GtkMenu pour commencer nous nous aurons dun menu Fichier

bull Six GtkMenuItem pour remplacer nos six boutons

Commenccedilons par la creacuteation du menu nous mettons ce code dans un nouveau fichier dont seul la fonction menu_newsera accessible

menucGtkMenuBar menu_new (gpointer user_data) GtkWidget p_menu_bar = NULL

p_menu_bar = gtk_menu_bar_new () return GTK_MENU_BAR (p_menu_bar)

Le paramegravetre user_data nous servira lors de la connexion des callbacks (nous en avons besoin pour les fonctionscb_new et cb_open)

Ensuite nous allons creacuteer notre sous menu Fichier

menuc Menu Fichier

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 35 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

menuc GtkWidget p_menu = NULL GtkWidget p_menu_item = NULL

p_menu = gtk_menu_new () p_menu_item = gtk_menu_item_new_with_mnemonic (_Fichier) gtk_menu_item_set_submenu (GTK_MENU_ITEM (p_menu_item) p_menu) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu_bar) p_menu_item) return GTK_MENU_BAR (p_menu_bar)

Un sous menu est en fait un GtkMenuItem auquel on assigne un GtkMenu Il faut bien sucircr terminer la creacuteation dusous-menu en lajoutant agrave la barre de menu

Pour finir nous creacuteons les eacuteleacutements du menu les GtkItemMenu Il existe plusieurs types deacuteleacutements (comparableaux diffeacuterents types de bouton) pour commencer nous nutiliserons que le type de base Comme cette opeacuteration estreacutepeacutetitive nous allons creacuteer une fonction pour le faire

menucstatic void menu_item_new (GtkMenu p_menu const gchar title GCallback callback gpointer user_data) GtkWidget p_menu_item = NULL

p_menu_item = gtk_menu_item_new_with_mnemonic (title) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu) p_menu_item) g_signal_connect (G_OBJECT (p_menu_item) activate callback user_data)

Pour permettre agrave lutilisateur dacceacuteder aux diffeacuterents eacuteleacutements du menu agrave laide de la touche ltAltgt nous utilisonsdes mneacutemoniques par exemple pour quitter leacutediteur il suffit de faite Alt+F puis Q Et voici le code pour creacuteer nossix eacuteleacutements du menu

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau G_CALLBACK (cb_new) user_data) menu_item_new (GTK_MENU (p_menu) _Ouvrir G_CALLBACK (cb_open) user_data) menu_item_new (GTK_MENU (p_menu) _Enregistrer G_CALLBACK (cb_save) user_data) menu_item_new (GTK_MENU (p_menu) Enregistrer _sous G_CALLBACK (cb_saveas) user_data) menu_item_new (GTK_MENU (p_menu) _Fermer G_CALLBACK (cb_close) user_data) menu_item_new (GTK_MENU (p_menu) _Quitter G_CALLBACK (cb_quit) user_data)

Voilagrave notre menu est creacuteeacute il nous reste plus quagrave linteacutegrer agrave notre fenecirctre

mainc gtk_box_pack_start (GTK_BOX (p_main_box) GTK_WIDGET (menu_new (p_text_view)) FALSE FALSE 0)

Le problegraveme cest que nous avons besoin de passer le GtkTextView lors de la creacuteation du menu (qui est utiliseacute par lesfonctions cb_new et cb_open) or celui-ci est creacuteeacute apregraves le menu (puisque nous creacuteons les widgets dans lordre ougrave ilfaut les inteacutegrer agrave linterface (8) ) nous devons creacuteer le GtkTextView (seul lappel agrave gtk_text_view_new est deacuteplaceacute)

XII-C - Code source

chapitre12zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 36 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIII - Les barres doutils

XIII-A - Aperccedilu

Cliquez pour agrandir

XIII-B - Creacuteation dune barre doutils

La creacuteation dune barre doutils ressemble fort agrave celle dun menu en plus simple puisquil ny a pas de sous menu on creacutee notre barre doutils (gtk_toolbar_new) puis les eacuteleacutements de la barre pour cela on utilise des boutons(gtk_tool_button_new_from_stock) que lon inseacutere dans la barre (gtk_toolbar_insert) Pas conseacutequent notre fichierbarreoutilsc ressemble agrave menuc

barreoutilscinclude ltgtkgtkhgtinclude callbackhinclude barreoutilsh

static void toolbar_item_new (GtkToolbar const gchar GCallback gpointer)

GtkToolbar toolbar_new (gpointer user_data) GtkWidget p_toolbar = NULL

p_toolbar = gtk_toolbar_new () toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_NEW G_CALLBACK (cb_new) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_OPEN G_CALLBACK (cb_open) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE G_CALLBACK (cb_save) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE_AS G_CALLBACK (cb_saveas) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_CLOSE G_CALLBACK (cb_close) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_QUIT G_CALLBACK (cb_quit) user_data) return GTK_TOOLBAR (p_toolbar)

static void toolbar_item_new (GtkToolbar p_toolbar const gchar stock_id GCallback callback gpointer user_data) GtkToolItem p_tool_item = NULL

p_tool_item = gtk_tool_button_new_from_stock (stock_id) g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data) gtk_toolbar_insert (p_toolbar p_tool_item -1)

Le code nest pas complet car lorsque jexeacutecute le programme GTK+ affiche en plus des icocircnes le texte sous lesboutons Pour modifier cela il suffit dajouter une ligne de code

barreoutilsc gtk_toolbar_set_style (GTK_TOOLBAR (p_toolbar) GTK_TOOLBAR_ICONS)

Pourquoi gtk_tool_button_new_from_stock retourne un GtkToolItem et non un GtkWidgetcomme nous avons eacuteteacute habitueacute jusquagrave preacutesent Il sagit dune bizarrerie de GTK+ dontje ne connais pas la raison

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 37 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour anticiper un changement dinterface (dans GTK+ 30 peut ecirctre ) nous aurions pueacutecrire

Gtkwidget p_tool_item = NULL

p_tool_item = GTK_WIDGET (gtk_tool_button_new_from_stock (stock_id))g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data)gtk_toolbar_insert (p_toolbar GTK_TOOL_ITEM (p_tool_item) -1)

XIII-C - Code source

chapitre13zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 38 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIV - Les racourcis clavier

XIV-A - Aperccedilu

Cliquez pour agrandir

XIV-B - Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mneacutemoniques ces derniers permettent dacceacuteder agrave un eacuteleacutementseacutequentiellement alors que les raccourcis appellent une fonction si lutilisateur appuie simultaneacutement sur une ouplusieurs touches (geacuteneacuteralement de la forme ltModificateurgtTouche ougrave Modificateur repreacutesente les touches ShiftAlt et Control) Ce raccourci peut ecirctre attacheacute agrave un eacuteleacutement du menu mais ceci nest pas obligatoire

Les raccourcis sont regroupeacutes en groupe dans un GtkAccelGroup quil faut commencer par creacuteer

raccourciscinclude ltgtkgtkhgtinclude callbackhinclude raccourcish

GtkAccelGroup accel_group_new (gpointer user_data) GtkAccelGroup p_accel_group = NULL

p_accel_group = gtk_accel_group_new () return p_accel_group

Vous commencez agrave avoir lhabitude de cette organisation nous allons donc creacuteer une fonction qui va se chargerdajouter un raccourci au groupe

raccourciscstatic void accelerator_new (GtkAccelGroup p_accel_group const gchar accelerator const gchar accel_path GCallback callback gpointer user_data) guint key GdkModifierType mods GClosure closure = NULL

gtk_accelerator_parse (accelerator ampkey ampmods) closure = g_cclosure_new (callback user_data NULL) gtk_accel_group_connect (p_accel_group key mods GTK_ACCEL_VISIBLE closure) gtk_accel_map_add_entry (accel_path key mods)

La fonction gtk_accelerator_parse permet de deacutecomposer une chaicircne de caractegraveres de la forme ltControlgtF1 ouencore ltAltgtA en numeacutero de touche et modificateur

En plus des touches pour creacuteer un raccourci clavier nous avons besoin dune fonction agrave appeler lorsque lutilisateurappuie sur les touches speacutecifieacutees gtk_accel_group_connect attend une fonction du type GClosure regardons ladocumentation de gobject pour savoir agrave quoi cela correspond

typedef struct

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 15 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

V - Afficher le contenue dun fichier

V-A - Aperccedilu

Cliquez pour agrandir

V-B - Saisir du texte

Les choses seacuterieuses vont commencer il sagit de mettre en place le widget qui va nous permettre dafficher etdeacutediter du texte Il sagit de la classe GtkTextView Gracircce agrave GTK+ la mise en place est toujours aussi simple

mainc GtkWidget p_text_view = NULL Creation de la zone de texte p_text_view = gtk_text_view_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_text_view TRUE TRUE 0)

Comme il sagit de la partie centrale de notre application nous demandons agrave ce quelle prenne le plus de placepossible (gracircce agrave la fonction gtk_box_pack_start)

Puisque nous voulons afficher les boutons en dessous de la zone de texte il faut ajouter ce morceau de code avantcelui creacuteant le bouton

V-C - Ouvrir un fichier

Maintenant nous avons une belle zone de texte il faut la remplir avec le contenu dun fichier Pour ce faire nousallons commencer par ajouter un bouton ouvrir

mainc Creation du bouton Ouvrir GtkWidget p_button = NULL

p_button = gtk_button_new_from_stock (GTK_STOCK_OPEN) g_signal_connect (G_OBJECT (p_button) clicked G_CALLBACK (cb_open) p_text_view) gtk_box_pack_start (GTK_BOX (p_main_box) p_button FALSE FALSE 0)

Si vous exeacutecutez le programme maintenant (3) vous remarquerez que les boutons sont ajouteacutes les uns en dessousdes autres ce qui diminue la zone de saisie (avec deux boutons ce nest pas gecircnant mais au bout dune dizaineccedila risque decirctre probleacutematique) Pour pallier ce problegraveme nous allons utiliser un nouveau style de GtkBox lesGtkButtonBox qui sont preacutevus pour contenir des boutons (ccedila tombe plutocirct bien D) Donc pour eacuteviter de diminuerla zone de saisie et comme nous avons de la place en largueur nous allons utiliser un GtkHButtonBox qui va ecirctreinclus dans la p_main_box Voici les modifications agrave effectuer

mainc GtkWidget p_button_box = NULL Creation du conteneur pour les boutons p_button_box = gtk_hbutton_box_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_button_box FALSE FALSE 0)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 16 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc gtk_box_pack_start (GTK_BOX (p_button_box) p_button FALSE FALSE 0) gtk_box_pack_start (GTK_BOX (p_button_box) p_button FALSE FALSE 0)

Maintenant il nous reste plus quagrave creacuteer la fonction cb_open dans le fichier callbackc pour linstant nous nouscontenterons douvrir toujours le mecircme fichier nous verrons plus tard comment laisser le choix agrave lutilisateur

callbackcdefine DEFAULT_FILE mainc

void cb_open (GtkWidget p_widget gpointer user_data) open_file (DEFAULT_FILE GTK_TEXT_VIEW (user_data))

Parametre inutilise (void)p_widget

Vous aurez compris que lon va deacuteleacuteguer tout le travail agrave la fonction open_file qui devra ouvrir le fichier dont le nomest passeacute en premier paramegravetre pour lafficher dans le GktTextView

Jai fait ce choix pour deux raisons le code dune fonction callback peut ecirctre tregraves conseacutequent (surtout si lon souhaitequelle affiche une boicircte de dialogue) et aussi parce que cb_open nest peut ecirctre pas la seule fonction agrave copierun fichier dans un GtkTextView (par exemple lors de la creacuteation dun nouveau fichier lon peut vouloir copier unsquelette de fichier)

Pour copier notre fichier plutocirct que dutiliser la fonction fgets nous allons nous servir de la glib (4) qui proposela fonction

gboolean g_file_get_contents (const gchar filename gchar contents gsize length GError error)

Qui nous renvoit le contenu du fichier nommeacute filename dans le tampon contents Il est possible de reacutecupeacuterer lenombre de caractegraveres copieacutes et retourne TRUE en cas de succegraves sinon FALSE et dans ce cas une structure de typeGError est creacutee pour en savoir plus sur le type derreur rencontreacute

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView else print_warning (Impossible douvrir le fichier sn file_name)

Je pense quun certain nombre dexplications simpose (surtout si je vais trop vite nheacutesitez pas agrave marrecircter )

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 17 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

bull g_return_if_fail est une macro qui peut ecirctre compareacutee agrave assert sauf quelle se contente de sortir de la fonctionsi lexpression passeacutee en paramegravetre est fausse Cest une meacutethode pratique pour veacuterifier la validiteacute desparamegravetres (si la fonction doit retourne une valeur utiliseacute plutocirct g_return_val_if_fail qui prend un secondparamegravetre la valeur agrave retourner)

bull Ensuite on essaie de reacutecupeacuterer le contenu de notre fichier

bull Si cela eacutechoue nous le signalons agrave lutilisateur agrave laide de la fonction print_warning

bull Le type gchar est une redeacutefinition du type char par la glib (il en va de mecircme pour tous les autres types du C)privileacutegiez ces types lorsque vous utilisez des fonctions de cette bibliothegraveques

Mais quest-ce donc cette fonction print_warning Cest une fonction que nous allons creacuteer semblable agrave printf quisignalera agrave lutilisateur quune erreur non critique est survenue Comme nous navons pas encore abordeacute les boicirctesde dialogue pour afficher un message il sagira pour linstant dune simple redeacutefinition de printf Pendant que noussommes dans laffichage des messages nous allons aussi creacuteer deux fonctions print_info et print_error qui vontrespectivement afficher un message dinformation et un message derreur critique (ce qui entraicircne la terminaison duprogramme) tout ceci dans un nouveau fichier errorc

errorhifndef H_ERRORdefine H_ERROR

void print_info (char )void print_warning (char )void print_error (char )

endif not H_ERROR

errorcinclude ltstdarghgtinclude ltstdiohgtinclude ltstdlibhgtinclude errorh

void print_info (char format ) va_list va

va_start (va format) printf (Information ) vprintf (format va) printf (n)

void print_warning (char format ) va_list va

va_start (va format) fprintf (stderr Erreur ) vfprintf (stderr format va) fprintf (stderr n)

void print_error (char format ) va_list va

va_start (va format) fprintf (stderr Erreur fatale ) vfprintf (stderr format va) fprintf (stderr n) exit (EXIT_FAILURE)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 18 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

Pour en finir avec louverture dun fichier il nous reste agrave copier contents dans le GtkTextView En fait le GtkTextViewne gegravere que la forme pour modifier le contenu il faut passer par les GtkTextBuffer Commenccedilons donc par reacutecupeacutererce fameux GtkTextBuffer

callbackc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (p_text_view)

Et pour finir on utilise la fonction

void gtk_text_buffer_insert (GtkTextBuffer buffer GtkTextIter iter const gchar text gint len)

Reacutecapitulons buffer est le GtkTextBuffer que lon vient de reacutecupeacuterer text cest le texte agrave afficher et len la taille dece dernier (ou -1 sil sagit dune chaicircne de caractegraveres au sens du langage C)

Mais quest-ce donc ce GtkTextIter On peut voir cela comme un curseur virtuel qui indique la position agrave laquelleeffectuer linsertion de texte dans le GtkTextBuffer (5) Allons voir ce que la documentation peut nous apprendreagrave leur sujet (6)

typedef struct GtkTextIter is an opaque datatype ignore all these fields Initialize the iter with gtk_text_buffer_get_iter_ functions GtkTextIter

Voilagrave on a notre solution suffit de rechercher les fonctions commenccedilant par gtk_text_buffer_get_iter_ voici la liste

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)

La fonction gtk_text_buffer_get_iter_at_line fait parfaitement laffaire

callbackc GtkTextIter iter

gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1)

Cependant si vous ne voulez pas avoir de problegravemes avec le codage des caractegraveres il vaut mieux convertir le codagelocal vers utf8 Voici le reacutesultat final

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 19 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gchar utf8 = NULL GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_text_buffer_insert (p_text_buffer ampiter utf8 -1) g_free (utf8) utf8 = NULL

V-D - La petite touche finale

Pour finir cette laborieuse partie sur une petite touche estheacutetique nous allons demander agrave GTK+ de nous lancerlapplication en plein eacutecran Pour se faire il suffit dajouter lors de la creacuteation de la fenecirctre principale

maincgtk_window_maximize (GTK_WINDOW (p_window))

On peut mecircme se permettre une pointe dexcentriciteacute en modifiant le titre de notre fenecirctre

maincgtk_window_set_title (GTK_WINDOW (p_window) Editeur de texte en GTK+)

V-E - Code source

chapitre5zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 20 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VI - Choisir un fichier

VI-A - Aperccedilu

Cliquez pour agrandir

VI-B - Utilisation dun GtkFileChooserFile

Jusquagrave preacutesent lutilisateur navait pas le choix quant au fichier agrave ouvrir heureusement GTK+ vient agrave notre aide gracircceau widget GtkFileChooserFile qui est tout simplement une boicircte de dialogue qui propose agrave lutilisateur de seacutelectionnerun fichier dans son arborescence disque

Commenccedilons par creacuteer notre boicircte de dialogue dans la fonction cb_open

callbackcvoid cb_open (GtkWidget p_widget gpointer user_data) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Ouvrir un fichier NULL GTK_FILE_CHOOSER_ACTION_OPEN GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_OPEN GTK_RESPONSE_ACCEPT NULL)

Cette fonction neacutecessite le titre de la boicircte de dialogue une fenecirctre parente le type daction (ici on souhaite ouvrir unfichier GTK+ autorisera lutilisateur agrave seacutelectionner uniquement les fichiers existants) Pour finir il sagit dun couple devaleurs GTK_STOCK_ITEMGTK_STOCK_RESPONSE qui permet de creacuteer un bouton utilisant le stock ID speacutecifieacuteet lorsque celui-ci est cliqueacute la fonction servant agrave lancer la boicircte de dialogue retournera le reacuteponse ID correspondantIl existe une seacuterie de valeurs deacutefinies par GTK+ quil est conseilleacute dutiliser

typedef enum GTK returns this if a response widget has no response_id or if the dialog gets programmatically hidden or destroyed GTK_RESPONSE_NONE = -1

GTK wont return these unless you pass them in as the response for an action widget They are for your convenience GTK_RESPONSE_REJECT = -2 GTK_RESPONSE_ACCEPT = -3

If the dialog is deleted GTK_RESPONSE_DELETE_EVENT = -4

These are returned from GTK dialogs and you can also use them yourself if you like GTK_RESPONSE_OK = -5 GTK_RESPONSE_CANCEL = -6 GTK_RESPONSE_CLOSE = -7 GTK_RESPONSE_YES = -8

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 21 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GTK_RESPONSE_NO = -9 GTK_RESPONSE_APPLY = -10 GTK_RESPONSE_HELP = -11 GtkResponseType

Nous indiquons la fin des couples stock idreacuteponse id avec la valeur NULL

Une fois la boicircte de dialogue creacuteee on demande agrave GTK+ de lafficher gracircce agrave la fonction gtk_dialog_run puis onreacutecupegravere sa valeur de retour qui correspond au bouton cliqueacute par lutilisateur

callbackc if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

Ici ce qui nous inteacuteresse cest lorsque que lutilisateur clique sur le bouton ouvrir (donc gtk_dialog_run renvoieGTK_RESPONSE_ACCEPT) dans ce cas il nous suffit de reacutecupeacuterer le nom du fichier seacutelectionneacute puis de louvrir

callbackc gchar file_name = NULL

file_name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) open_file (file_name GTK_TEXT_VIEW (user_data)) g_free (file_name) file_name = NULL

Pour finir dans tous les cas on noublie pas de deacutetruire la boicircte de dialogue

callbackc gtk_widget_destroy (p_dialog)

Et voilagrave le travail lutilisateur peut ouvrir le fichier quil souhaite

VI-C - Code source

chapitre6zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 22 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VII - Interlude

Avant daller plus loin dans lameacutelioration de linterface de notre eacutediteur il est neacutecessaire de modifier sonfonctionnement interne (ne vous inquieacutetez je nai pas dit chambouler) en effet souvenez-vous dans lintroduction jaieacutevoqueacute la possibiliteacutes douvrir plusieurs documents gracircce agrave un systegraveme donglets Pour cela il faut sauvegarder lesproprieacuteteacutes de chaque document ouvert Pris agrave temps ce genre de modification nest pas trop lourde mais si nousattendons cela risque de devenir un vrai casse tecircte

Pour cela nous allons utiliser une structure de donneacutee pour chaque document ouvert qui devra garder en meacutemoirele chemin complet du fichier (ou NULL si le document nest pas encore sauvegarder) sil agrave eacutetait modifier depuis laderniegravere sauvegarde et le GtkTextView qui sert agrave son affichage Voici donc la structure qui va nous servir

documenthtypedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

Sachant que nous serons ameneacute agrave stocker plusieurs occurrences de cette structure il serait bon de reacutefleacutechir degravesmaintenant agrave la structure de donneacutee agrave utiliser pour les stocker La premiegravere ideacutee qui vient agrave lesprit est un tableaualloueacute dynamiquement cependant lutilisateur peut souhaiter fermer un document qui se trouve au milieu on estalors obligeacute de deacutecaler toutes les cellules en amont Dans ce cas il parait naturel dutiliser une liste chaicircneacutee Parchance la glib propose une bibliothegraveque de gestion des listes chaicircneacutees cela nous fera gagner du temps le momentvenu Pour linstant on se contente de creacuteer une structure de donneacutees qui contiendra tous les documents ouverts(stockeacutee dans une GList) et un pointeur sur le document actif (actuellement comme nous navons quun documentouvert en mecircme temps on manipulera uniquement ce pointeur)

documenthtypedef struct GList tous document_t actif docs_t

Maintenant se pose le problegraveme de savoir comment transmettre cette structure On pourrait se servir du paramegravetreuser_data preacutesent dans toutes les fonctions callback mais certaines fonctions utilise deacutejagrave ce paramegravetre (la fonctioncb_open par exemple) il faudrait creacuteer un champs suppleacutementaire dans notre structure documents_s Une solutionplus simple est de creacuteer une variable globale agrave lensemble du programme Ceux qui passe reacuteguliegraverement sur le forumC savent que cest fortement deacuteconseilleacute mais ici nous nous trouvons dans lune des rares exceptions agrave la regravegle Detoute faccedilon cela revient au mecircme que de passer ladresse de notre structure agrave toutes les fonctions callback Nousdeacutefinissons donc un nouveau fichier den-tecircte

documenthifndef H_DOCUMENTdefine H_DOCUMENT

include ltgtkgtkhgt

typedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 23 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

documenthtypedef struct GList tous document_t actif docs_t

extern docs_t docs

endif not H_DOCUMENT

Et dans le fichier mainc

maincinclude documenth

docs_t docs = NULL NULL

Pour linstant la seule fonction qui modifie leacutetat dun document est la fonction open_file il faut donc inclure documenthdans callbackc et modifier leacutegegraverement la fonction pour enregistrer le document ouvert

callbackc if (g_file_get_contents (file_name ampcontents NULL NULL)) Pour linstant il faut allouer la memoire par la suite on modifira simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = g_strdup (file_name) Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = p_text_view Le document vient detre ouvert il nest donc pas modifie docsactif-gtsauve = TRUE

Ne soyez pas choqueacute si je ne teste pas le retour de la fonction g_malloc pour veacuterifier quilnest pas NULL En effet cette derniegravere met fin agrave lapplication si lallocation eacutechoue

VII-A - Code source

chapitre7zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 24 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VIII - Sauvegarder les modification

VIII-A - Aperccedilu

Cliquez pour agrandir

VIII-B - Enregistrer

Avant de pouvoir sauvegarder un document il faut quil soit modifieacute Comment savoir que le contenu du fichier a eacuteteacutemodifier Gracircce au signal changed du GtkTextBuffer que nous interceptons gracircce agrave la fonction cb_modifie

mainc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (p_text_view)) g_signal_connect (G_OBJECT (p_text_buffer) changed G_CALLBACK (cb_modifie) NULL)

Cette derniegravere modifie simplement le champ sauve du document

callbackcvoid cb_modifie (GtkWidget p_widget gpointer user_data) if (docsactif) docsactif-gtsauve = FALSE

Pour la sauvegarde il faut distinguer deux cas soit il sagit de la premiegravere sauvegarde du fichier il faut alors demanderle nom du fichier agrave lutilisateur (cela ressemble fortement agrave louverture dun fichier) soit le fichier est deacutejagrave preacutesent surle disque il suffit de remplacer son contenu par celui du GtkTextViewer Nous avons convenu quun fichier qui neacutetaitpas encore enregistreacute avait sa proprieacuteteacute chemin agrave NULL

Bien sucircr cela na lieu que si un fichier est ouvert et quil a eacuteteacute modifieacute depuis sa derniegravere sauvegarde

callbackcvoid cb_save (GtkWidget p_widget gpointer user_data) if (docsactif) if (docsactif-gtsauve) Le fichier na pas encore ete enregistre if (docsactif-gtchemin) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Sauvegarder le fichier NULL GTK_FILE_CHOOSER_ACTION_SAVE GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_SAVE GTK_RESPONSE_ACCEPT NULL) if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 25 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc docsactif-gtchemin = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) gtk_widget_destroy (p_dialog) Soit le fichier a deja ete enregistre soit lutilisateur vient de nous fournir son nouvel enplacement on peut donc lenregistrer if (docsactif-gtchemin) else print_warning (Aucun document ouvert)

Il nous reste plus quagrave reacutecupeacuterer le contenu du GtkTextViewer et le copier dans le fichier chemin sans oublier dereconvertir le texte dans le codage local

callbackc FILE fichier = NULL

fichier = fopen (docsactif-gtchemin w) if (fichier) gchar contents = NULL gchar locale = NULL GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) contents = gtk_text_buffer_get_text (p_text_buffer ampstart ampend FALSE) locale = g_locale_from_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL fprintf (fichier s locale) g_free (locale) locale = NULL fclose (fichier) fichier = NULL docsactif-gtsauve = TRUE else print_warning (Impossible de sauvegarder le fichier s docsactif-gtchemin)

Le dernier paramegravetre de la fonction gtk_text_buffer_get_text est mis agrave FALSE car nous ne voulons pas enregistrerles caractegraveres invisibles preacutesent dans le GtkTextBuffer Ces caractegraveres servent agrave mettre en forme le texte (taillecouleur) nous pourrions creacuteer un nouveau format de fichier pour enregistrer la mise en forme

VIII-C - Enregistrer sous

Pour enregistrer notre document sous un autre nom il suffit de faire croire agrave cb_save que le document na pas encoreeacutetait enregistreacute tout simplement en changeant chemin agrave NULL et sauve agrave FALSE

callbackcvoid cb_saveas (GtkWidget p_widget gpointer user_data)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 26 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (docsactif) document_t tmp = docsactif

docsactif-gtchemin = NULL docsactif-gtsauve = FALSE cb_save (p_widget user_data) if (docsactif-gtsauve) (docsactif) = tmp else print_warning (Aucun document ouvert)

Il ne faut pas oublier que lutilisateur peut annuler lenregistrement de ce fait nous sauvegardons leacutetat du documentet si la sauvegarde na pas eu lieu on le restaure

VIII-D - Code source

chapitre8zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 27 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IX - Creacuteer un nouveau document

IX-A - Aperccedilu

Cliquez pour agrandir

IX-B - Nouveau fichier

Maintenant que lutilisateur peut ouvrir et fermer un fichier il est inteacuteressant de lui donner la possibiliteacute den creacuteerun nouveau Je ne reviens pas sur la creacuteation du bouton (ccedila devrait deacutejagrave ecirctre fait D) passons directement agrave lafonction cb_new

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) Pour linstant il faut allouer la memoire par la suite on modifiera simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = NULL Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = GTK_TEXT_VIEW (user_data) Le document vient detre creer il nest donc pas modifie docsactif-gtsauve = TRUE gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Je ne sais pas vous mais pour ma part jai fait un copiercoller de la fonction open_file Et oui ouvrir un document peutse reacutesumer agrave creacuteer un document vide puis remplir le GtkTextView avec le fichier souhaiteacute On peut donc simplifiernotre fonction open_file ainsi

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

cb_new (NULL p_text_view) gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE) p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1) Nous sommes obliges de remetre sauve a TRUE car linsertion du contenu du fichier dans le GtkTextView a appele cb_modfie docsactif-gtsauve = TRUE else print_warning (Impossible douvrir le fichier sn file_name)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 28 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc

Cest beau la factorisation du code Par contre nous sommes obligeacutes de remettre sauve agrave TRUE car nous avonsmodifieacute le GtkTextBuffer

IX-C - Code source

chapitre9zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 29 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

X - Fermer

X-A - Aperccedilu

Cliquez pour agrandir

X-B - Fermer un fichier

Maintenant que nous allouons de la meacutemoire il faut la libeacuterer agrave un endroit Logiquement cela va ecirctre fait agrave la fermeturedu document en guise dexercice je vous laisse creacuteer le bouton dans notre boicircte agrave bouton

Allez je vous aide le stock id correspondant est GTK_STOCK_CLOSE

Voilagrave maintenant si tout cest bien passeacute vous devriez ecirctre arriveacute dans le fichier callbackc avec quelque choseressemblant agrave

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data)

Lorsque lon ferme un document il faut vider le GtkTextView (avec les onglets on se contentera de le supprimer)pour cela il faut reacutecupeacuterer le deacutebut et la fin du GtkTextBuffer et demander agrave GTK+ de supprimer tout ce qui ce trouveentre les deux iteacuterateurs

callbackc Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) gtk_text_buffer_delete (p_text_buffer ampstart ampend) else print_warning (Aucun document ouvert)

Bien sucircr il ne faut pas oublier de libeacuterer la meacutemoire

callbackc g_free (docsactif-gtchemin) docsactif-gtchemin = NULL docsactif-gtp_text_view = NULL g_free (docsactif) docsactif = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 30 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour symboliser la fermeture dun document nous deacutesactivons le GtkTextView lors de la fermeture (ne pas oublierde le faire aussi dans mainc)

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) FALSE)

Et nous le reacuteactivons lors de louverture si celle si reacuteussie

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Lorsque lutilisateur quitte lapplication il faut bien sucircr fermer le document sil y en a un ouvert

void cb_quit (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data) gtk_main_quit()

Et aussi lorsquil creacuteeacute un nouveau document (et par conseacutequent lorsquil ouvre un fichier puisque lon fait appel agravecb_new)

void cb_new (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data)

X-C - Enregistrer avant de fermer

Si le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde geacuteneacuteralement le programme le signale agrave lutilisateur etlui propose de sauvegarder ou dannuler la fermeture Pour se faire nous devons modifier la fonction cb_close avantde fermer le document nous allons afficher une boicircte de dialogue

Pour creacuteer une boicircte de dialogue simplement il existe la classe GtkDialog et comme nous avons besoin de boutons(pour que lutilisateur fasse son choix) nous allons creacuteer notre boicircte avec la fonction

GtkWidget gtk_dialog_new_with_buttons (const gchar title GtkWindow parent GtkDialogFlags flags const gchar first_button_text )

Nous retrouvons les mecircmes options que pour le GtkFileChooserDialog mis agrave part option du type GtkDialogFlags

typedef enum GTK_DIALOG_MODAL = 1 ltlt 0 appel gtk_window_set_modal (win TRUE) GTK_DIALOG_DESTROY_WITH_PARENT = 1 ltlt 1 appel gtk_window_set_destroy_with_parent () GTK_DIALOG_NO_SEPARATOR = 1 ltlt 2 Pas de barre de separation au dessus des boutons GtkDialogFlags

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 31 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Nous nous contenterons de rendre notre fenecirctre modale (7)

Pour avoir accegraves agrave notre fenecirctre principale nous ajoutons un champs p_main_window agrave notre structure globaledocs_t que nous initialisons dans la fonction main

mainc docsp_main_window = GTK_WINDOW (p_window)

Il nous reste plus qua creacuteer notre boicircte de dialogue avec trois boutons Oui Non Annuler

callbackc if (docsactif-gtsauve) GtkWidget p_dialog = NULL

p_dialog = gtk_dialog_new_with_buttons (Sauvegarder docsp_main_window GTK_DIALOG_MODAL GTK_STOCK_YES GTK_RESPONSE_YES GTK_STOCK_NO GTK_RESPONSE_NO GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL NULL)

Nous obtenons donc une structure de type GtkDialog

typedef struct GtkWidget vbox GtkWidget action_area GtkDialog

Nous remarquons que cette structure contient deux membres qui permettent dacceacuteder agrave une GtkBox ougrave nous allonsajouter le contenu de la fenecirctre et agrave la partie contenant les boutons

Ensuite la construction de la fenecirctre est identique agrave celle de la fenecirctre principale ici nous nous contenterons dajouterun GtkLabel

callbackc GtkWidget p_label = NULL p_label = gtk_label_new (Voulez-vous sauvegarder les modifications ) gtk_box_pack_start (GTK_BOX (GTK_DIALOG (p_dialog)-gtvbox) p_label TRUE TRUE 0)

Une fois notre fenecirctre precircte il suffit de faire appel agrave la fonction gtk_dialog_run qui va afficher notre GtkDialog et nousretourner le reacuteponse id correspondant au bouton cliqueacute par lutilisateur

callbackc switch (gtk_dialog_run (GTK_DIALOG (p_dialog))) case GTK_RESPONSE_YES cb_save (p_widget user_data) break case GTK_RESPONSE_NO break case GTK_RESPONSE_CANCEL gtk_widget_destroy (p_dialog) return break

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 32 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc gtk_widget_destroy (p_dialog)

Si lutilisateur clique sur non on ne fait rien (le document sera simplement fermeacute) sur oui on enregistre avant defermer et pour finir sil annule on quitte la fonction

X-D - Code source

chapitre10zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 33 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XI - Les barres de deacutefilement

XI-A - Aperccedilu

Cliquez pour agrandir

XI-B - Ajouter des barres de deacutefilement

Apregraves le dernier chapitre quelque peu laborieux voici une partie plus simple mais qui va rendre notre applicationplus pratique En effet si vous avez essayeacute douvrir un fichier de grande taille vous avez pu remarquer que pourpouvoir lire la fin du fichier il fallait utiliser les touches du clavier pas tregraves convivial

Pour rendre la navigation plus aiseacutee on utilise des barres de deacutefilement

mainc GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_scrolled_window TRUE TRUE 0)

Creation de la zone de texte gtk_container_add (GTK_CONTAINER (p_scrolled_window) p_text_view)

Le constructeur de notre GtkScrolledWindow prend en argument deux GtkAdjustment qui permettent de deacutefinirdiffeacuterentes proprieacuteteacutes de la barre de deacutefilement (taille dune page la position de deacutepart) nous laissons GTK+ faireen passant NULL

Cest un bon deacutebut mais estheacutetiquement on peut faire mieux mecircme sil nest pas utile davoir une barre de deacutefilementelle est quand mecircme afficheacutee On peut demander agrave GTK+ de les afficher que si cela est neacutecessaire

mainc gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC)

En fait nous avons de la chance car la classe GtkTextView fait partie des widget qui supporte de faccedilon native les barresde deacutefilement Comment le savoir Ce genre de widget possegravede une ou deux proprieacuteteacutes de type GtkAdjustment (unepour la barre verticale lautre pour la barre horizontale) Actuellement seulement trois classes en sont capables lesGtkTextView les GtkTreeView et les GtkLayout

Comment faire pour les autres widgets Il faut passer par une classe adaptateur GtkViewport afin de creacuteer lesGtkAdjustment

XI-C - Code source

chapitre11zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 34 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XII - Les menus

XII-A - Aperccedilu

Cliquez pour agrandir

XII-B - Creacuteation du menu

Pour simplifier nous avons utiliseacute des boutons pour permettre agrave lutilisateur de creacuteer un document ouvrir un fichierMais il est plus courant dutiliser un menu pour afficher ces options GTK+ propose trois maniegraveres de creacuteer un menu

bull GtkItemFactory cette meacutethode est obsolegravete depuis la version 24 de GTK+

bull GtkUIManager cest ce quon appel une usine agrave gaz pour en savoir plus vous pouvez vous reporter aututoriel Utilisation de GtkUIManager

bull GtkMenu cest ce widget que nous allons eacutetudier il permet de creacuteer un menu manuellement (agrave lopposeacute deGtkUIManager)

Un menu selon GTK+ est composeacute de plusieurs eacuteleacutements

bull GtkMenuBar la barre de menu elle-mecircme

bull GtkMenu la partie deacuteroulante qui contient les diffeacuterents eacuteleacutements

bull GtkMenuItem cest sur ce widget que lutilisateur clique pour lancer une action

Pour commencer faisons linventaire de ce que nous avons besoin

bull Un GtkMenuBar qui sert de base au menu

bull Un GtkMenu pour commencer nous nous aurons dun menu Fichier

bull Six GtkMenuItem pour remplacer nos six boutons

Commenccedilons par la creacuteation du menu nous mettons ce code dans un nouveau fichier dont seul la fonction menu_newsera accessible

menucGtkMenuBar menu_new (gpointer user_data) GtkWidget p_menu_bar = NULL

p_menu_bar = gtk_menu_bar_new () return GTK_MENU_BAR (p_menu_bar)

Le paramegravetre user_data nous servira lors de la connexion des callbacks (nous en avons besoin pour les fonctionscb_new et cb_open)

Ensuite nous allons creacuteer notre sous menu Fichier

menuc Menu Fichier

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 35 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

menuc GtkWidget p_menu = NULL GtkWidget p_menu_item = NULL

p_menu = gtk_menu_new () p_menu_item = gtk_menu_item_new_with_mnemonic (_Fichier) gtk_menu_item_set_submenu (GTK_MENU_ITEM (p_menu_item) p_menu) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu_bar) p_menu_item) return GTK_MENU_BAR (p_menu_bar)

Un sous menu est en fait un GtkMenuItem auquel on assigne un GtkMenu Il faut bien sucircr terminer la creacuteation dusous-menu en lajoutant agrave la barre de menu

Pour finir nous creacuteons les eacuteleacutements du menu les GtkItemMenu Il existe plusieurs types deacuteleacutements (comparableaux diffeacuterents types de bouton) pour commencer nous nutiliserons que le type de base Comme cette opeacuteration estreacutepeacutetitive nous allons creacuteer une fonction pour le faire

menucstatic void menu_item_new (GtkMenu p_menu const gchar title GCallback callback gpointer user_data) GtkWidget p_menu_item = NULL

p_menu_item = gtk_menu_item_new_with_mnemonic (title) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu) p_menu_item) g_signal_connect (G_OBJECT (p_menu_item) activate callback user_data)

Pour permettre agrave lutilisateur dacceacuteder aux diffeacuterents eacuteleacutements du menu agrave laide de la touche ltAltgt nous utilisonsdes mneacutemoniques par exemple pour quitter leacutediteur il suffit de faite Alt+F puis Q Et voici le code pour creacuteer nossix eacuteleacutements du menu

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau G_CALLBACK (cb_new) user_data) menu_item_new (GTK_MENU (p_menu) _Ouvrir G_CALLBACK (cb_open) user_data) menu_item_new (GTK_MENU (p_menu) _Enregistrer G_CALLBACK (cb_save) user_data) menu_item_new (GTK_MENU (p_menu) Enregistrer _sous G_CALLBACK (cb_saveas) user_data) menu_item_new (GTK_MENU (p_menu) _Fermer G_CALLBACK (cb_close) user_data) menu_item_new (GTK_MENU (p_menu) _Quitter G_CALLBACK (cb_quit) user_data)

Voilagrave notre menu est creacuteeacute il nous reste plus quagrave linteacutegrer agrave notre fenecirctre

mainc gtk_box_pack_start (GTK_BOX (p_main_box) GTK_WIDGET (menu_new (p_text_view)) FALSE FALSE 0)

Le problegraveme cest que nous avons besoin de passer le GtkTextView lors de la creacuteation du menu (qui est utiliseacute par lesfonctions cb_new et cb_open) or celui-ci est creacuteeacute apregraves le menu (puisque nous creacuteons les widgets dans lordre ougrave ilfaut les inteacutegrer agrave linterface (8) ) nous devons creacuteer le GtkTextView (seul lappel agrave gtk_text_view_new est deacuteplaceacute)

XII-C - Code source

chapitre12zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 36 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIII - Les barres doutils

XIII-A - Aperccedilu

Cliquez pour agrandir

XIII-B - Creacuteation dune barre doutils

La creacuteation dune barre doutils ressemble fort agrave celle dun menu en plus simple puisquil ny a pas de sous menu on creacutee notre barre doutils (gtk_toolbar_new) puis les eacuteleacutements de la barre pour cela on utilise des boutons(gtk_tool_button_new_from_stock) que lon inseacutere dans la barre (gtk_toolbar_insert) Pas conseacutequent notre fichierbarreoutilsc ressemble agrave menuc

barreoutilscinclude ltgtkgtkhgtinclude callbackhinclude barreoutilsh

static void toolbar_item_new (GtkToolbar const gchar GCallback gpointer)

GtkToolbar toolbar_new (gpointer user_data) GtkWidget p_toolbar = NULL

p_toolbar = gtk_toolbar_new () toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_NEW G_CALLBACK (cb_new) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_OPEN G_CALLBACK (cb_open) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE G_CALLBACK (cb_save) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE_AS G_CALLBACK (cb_saveas) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_CLOSE G_CALLBACK (cb_close) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_QUIT G_CALLBACK (cb_quit) user_data) return GTK_TOOLBAR (p_toolbar)

static void toolbar_item_new (GtkToolbar p_toolbar const gchar stock_id GCallback callback gpointer user_data) GtkToolItem p_tool_item = NULL

p_tool_item = gtk_tool_button_new_from_stock (stock_id) g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data) gtk_toolbar_insert (p_toolbar p_tool_item -1)

Le code nest pas complet car lorsque jexeacutecute le programme GTK+ affiche en plus des icocircnes le texte sous lesboutons Pour modifier cela il suffit dajouter une ligne de code

barreoutilsc gtk_toolbar_set_style (GTK_TOOLBAR (p_toolbar) GTK_TOOLBAR_ICONS)

Pourquoi gtk_tool_button_new_from_stock retourne un GtkToolItem et non un GtkWidgetcomme nous avons eacuteteacute habitueacute jusquagrave preacutesent Il sagit dune bizarrerie de GTK+ dontje ne connais pas la raison

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 37 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour anticiper un changement dinterface (dans GTK+ 30 peut ecirctre ) nous aurions pueacutecrire

Gtkwidget p_tool_item = NULL

p_tool_item = GTK_WIDGET (gtk_tool_button_new_from_stock (stock_id))g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data)gtk_toolbar_insert (p_toolbar GTK_TOOL_ITEM (p_tool_item) -1)

XIII-C - Code source

chapitre13zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 38 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIV - Les racourcis clavier

XIV-A - Aperccedilu

Cliquez pour agrandir

XIV-B - Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mneacutemoniques ces derniers permettent dacceacuteder agrave un eacuteleacutementseacutequentiellement alors que les raccourcis appellent une fonction si lutilisateur appuie simultaneacutement sur une ouplusieurs touches (geacuteneacuteralement de la forme ltModificateurgtTouche ougrave Modificateur repreacutesente les touches ShiftAlt et Control) Ce raccourci peut ecirctre attacheacute agrave un eacuteleacutement du menu mais ceci nest pas obligatoire

Les raccourcis sont regroupeacutes en groupe dans un GtkAccelGroup quil faut commencer par creacuteer

raccourciscinclude ltgtkgtkhgtinclude callbackhinclude raccourcish

GtkAccelGroup accel_group_new (gpointer user_data) GtkAccelGroup p_accel_group = NULL

p_accel_group = gtk_accel_group_new () return p_accel_group

Vous commencez agrave avoir lhabitude de cette organisation nous allons donc creacuteer une fonction qui va se chargerdajouter un raccourci au groupe

raccourciscstatic void accelerator_new (GtkAccelGroup p_accel_group const gchar accelerator const gchar accel_path GCallback callback gpointer user_data) guint key GdkModifierType mods GClosure closure = NULL

gtk_accelerator_parse (accelerator ampkey ampmods) closure = g_cclosure_new (callback user_data NULL) gtk_accel_group_connect (p_accel_group key mods GTK_ACCEL_VISIBLE closure) gtk_accel_map_add_entry (accel_path key mods)

La fonction gtk_accelerator_parse permet de deacutecomposer une chaicircne de caractegraveres de la forme ltControlgtF1 ouencore ltAltgtA en numeacutero de touche et modificateur

En plus des touches pour creacuteer un raccourci clavier nous avons besoin dune fonction agrave appeler lorsque lutilisateurappuie sur les touches speacutecifieacutees gtk_accel_group_connect attend une fonction du type GClosure regardons ladocumentation de gobject pour savoir agrave quoi cela correspond

typedef struct

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 16 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc gtk_box_pack_start (GTK_BOX (p_button_box) p_button FALSE FALSE 0) gtk_box_pack_start (GTK_BOX (p_button_box) p_button FALSE FALSE 0)

Maintenant il nous reste plus quagrave creacuteer la fonction cb_open dans le fichier callbackc pour linstant nous nouscontenterons douvrir toujours le mecircme fichier nous verrons plus tard comment laisser le choix agrave lutilisateur

callbackcdefine DEFAULT_FILE mainc

void cb_open (GtkWidget p_widget gpointer user_data) open_file (DEFAULT_FILE GTK_TEXT_VIEW (user_data))

Parametre inutilise (void)p_widget

Vous aurez compris que lon va deacuteleacuteguer tout le travail agrave la fonction open_file qui devra ouvrir le fichier dont le nomest passeacute en premier paramegravetre pour lafficher dans le GktTextView

Jai fait ce choix pour deux raisons le code dune fonction callback peut ecirctre tregraves conseacutequent (surtout si lon souhaitequelle affiche une boicircte de dialogue) et aussi parce que cb_open nest peut ecirctre pas la seule fonction agrave copierun fichier dans un GtkTextView (par exemple lors de la creacuteation dun nouveau fichier lon peut vouloir copier unsquelette de fichier)

Pour copier notre fichier plutocirct que dutiliser la fonction fgets nous allons nous servir de la glib (4) qui proposela fonction

gboolean g_file_get_contents (const gchar filename gchar contents gsize length GError error)

Qui nous renvoit le contenu du fichier nommeacute filename dans le tampon contents Il est possible de reacutecupeacuterer lenombre de caractegraveres copieacutes et retourne TRUE en cas de succegraves sinon FALSE et dans ce cas une structure de typeGError est creacutee pour en savoir plus sur le type derreur rencontreacute

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView else print_warning (Impossible douvrir le fichier sn file_name)

Je pense quun certain nombre dexplications simpose (surtout si je vais trop vite nheacutesitez pas agrave marrecircter )

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 17 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

bull g_return_if_fail est une macro qui peut ecirctre compareacutee agrave assert sauf quelle se contente de sortir de la fonctionsi lexpression passeacutee en paramegravetre est fausse Cest une meacutethode pratique pour veacuterifier la validiteacute desparamegravetres (si la fonction doit retourne une valeur utiliseacute plutocirct g_return_val_if_fail qui prend un secondparamegravetre la valeur agrave retourner)

bull Ensuite on essaie de reacutecupeacuterer le contenu de notre fichier

bull Si cela eacutechoue nous le signalons agrave lutilisateur agrave laide de la fonction print_warning

bull Le type gchar est une redeacutefinition du type char par la glib (il en va de mecircme pour tous les autres types du C)privileacutegiez ces types lorsque vous utilisez des fonctions de cette bibliothegraveques

Mais quest-ce donc cette fonction print_warning Cest une fonction que nous allons creacuteer semblable agrave printf quisignalera agrave lutilisateur quune erreur non critique est survenue Comme nous navons pas encore abordeacute les boicirctesde dialogue pour afficher un message il sagira pour linstant dune simple redeacutefinition de printf Pendant que noussommes dans laffichage des messages nous allons aussi creacuteer deux fonctions print_info et print_error qui vontrespectivement afficher un message dinformation et un message derreur critique (ce qui entraicircne la terminaison duprogramme) tout ceci dans un nouveau fichier errorc

errorhifndef H_ERRORdefine H_ERROR

void print_info (char )void print_warning (char )void print_error (char )

endif not H_ERROR

errorcinclude ltstdarghgtinclude ltstdiohgtinclude ltstdlibhgtinclude errorh

void print_info (char format ) va_list va

va_start (va format) printf (Information ) vprintf (format va) printf (n)

void print_warning (char format ) va_list va

va_start (va format) fprintf (stderr Erreur ) vfprintf (stderr format va) fprintf (stderr n)

void print_error (char format ) va_list va

va_start (va format) fprintf (stderr Erreur fatale ) vfprintf (stderr format va) fprintf (stderr n) exit (EXIT_FAILURE)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 18 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

Pour en finir avec louverture dun fichier il nous reste agrave copier contents dans le GtkTextView En fait le GtkTextViewne gegravere que la forme pour modifier le contenu il faut passer par les GtkTextBuffer Commenccedilons donc par reacutecupeacutererce fameux GtkTextBuffer

callbackc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (p_text_view)

Et pour finir on utilise la fonction

void gtk_text_buffer_insert (GtkTextBuffer buffer GtkTextIter iter const gchar text gint len)

Reacutecapitulons buffer est le GtkTextBuffer que lon vient de reacutecupeacuterer text cest le texte agrave afficher et len la taille dece dernier (ou -1 sil sagit dune chaicircne de caractegraveres au sens du langage C)

Mais quest-ce donc ce GtkTextIter On peut voir cela comme un curseur virtuel qui indique la position agrave laquelleeffectuer linsertion de texte dans le GtkTextBuffer (5) Allons voir ce que la documentation peut nous apprendreagrave leur sujet (6)

typedef struct GtkTextIter is an opaque datatype ignore all these fields Initialize the iter with gtk_text_buffer_get_iter_ functions GtkTextIter

Voilagrave on a notre solution suffit de rechercher les fonctions commenccedilant par gtk_text_buffer_get_iter_ voici la liste

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)

La fonction gtk_text_buffer_get_iter_at_line fait parfaitement laffaire

callbackc GtkTextIter iter

gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1)

Cependant si vous ne voulez pas avoir de problegravemes avec le codage des caractegraveres il vaut mieux convertir le codagelocal vers utf8 Voici le reacutesultat final

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 19 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gchar utf8 = NULL GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_text_buffer_insert (p_text_buffer ampiter utf8 -1) g_free (utf8) utf8 = NULL

V-D - La petite touche finale

Pour finir cette laborieuse partie sur une petite touche estheacutetique nous allons demander agrave GTK+ de nous lancerlapplication en plein eacutecran Pour se faire il suffit dajouter lors de la creacuteation de la fenecirctre principale

maincgtk_window_maximize (GTK_WINDOW (p_window))

On peut mecircme se permettre une pointe dexcentriciteacute en modifiant le titre de notre fenecirctre

maincgtk_window_set_title (GTK_WINDOW (p_window) Editeur de texte en GTK+)

V-E - Code source

chapitre5zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 20 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VI - Choisir un fichier

VI-A - Aperccedilu

Cliquez pour agrandir

VI-B - Utilisation dun GtkFileChooserFile

Jusquagrave preacutesent lutilisateur navait pas le choix quant au fichier agrave ouvrir heureusement GTK+ vient agrave notre aide gracircceau widget GtkFileChooserFile qui est tout simplement une boicircte de dialogue qui propose agrave lutilisateur de seacutelectionnerun fichier dans son arborescence disque

Commenccedilons par creacuteer notre boicircte de dialogue dans la fonction cb_open

callbackcvoid cb_open (GtkWidget p_widget gpointer user_data) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Ouvrir un fichier NULL GTK_FILE_CHOOSER_ACTION_OPEN GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_OPEN GTK_RESPONSE_ACCEPT NULL)

Cette fonction neacutecessite le titre de la boicircte de dialogue une fenecirctre parente le type daction (ici on souhaite ouvrir unfichier GTK+ autorisera lutilisateur agrave seacutelectionner uniquement les fichiers existants) Pour finir il sagit dun couple devaleurs GTK_STOCK_ITEMGTK_STOCK_RESPONSE qui permet de creacuteer un bouton utilisant le stock ID speacutecifieacuteet lorsque celui-ci est cliqueacute la fonction servant agrave lancer la boicircte de dialogue retournera le reacuteponse ID correspondantIl existe une seacuterie de valeurs deacutefinies par GTK+ quil est conseilleacute dutiliser

typedef enum GTK returns this if a response widget has no response_id or if the dialog gets programmatically hidden or destroyed GTK_RESPONSE_NONE = -1

GTK wont return these unless you pass them in as the response for an action widget They are for your convenience GTK_RESPONSE_REJECT = -2 GTK_RESPONSE_ACCEPT = -3

If the dialog is deleted GTK_RESPONSE_DELETE_EVENT = -4

These are returned from GTK dialogs and you can also use them yourself if you like GTK_RESPONSE_OK = -5 GTK_RESPONSE_CANCEL = -6 GTK_RESPONSE_CLOSE = -7 GTK_RESPONSE_YES = -8

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 21 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GTK_RESPONSE_NO = -9 GTK_RESPONSE_APPLY = -10 GTK_RESPONSE_HELP = -11 GtkResponseType

Nous indiquons la fin des couples stock idreacuteponse id avec la valeur NULL

Une fois la boicircte de dialogue creacuteee on demande agrave GTK+ de lafficher gracircce agrave la fonction gtk_dialog_run puis onreacutecupegravere sa valeur de retour qui correspond au bouton cliqueacute par lutilisateur

callbackc if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

Ici ce qui nous inteacuteresse cest lorsque que lutilisateur clique sur le bouton ouvrir (donc gtk_dialog_run renvoieGTK_RESPONSE_ACCEPT) dans ce cas il nous suffit de reacutecupeacuterer le nom du fichier seacutelectionneacute puis de louvrir

callbackc gchar file_name = NULL

file_name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) open_file (file_name GTK_TEXT_VIEW (user_data)) g_free (file_name) file_name = NULL

Pour finir dans tous les cas on noublie pas de deacutetruire la boicircte de dialogue

callbackc gtk_widget_destroy (p_dialog)

Et voilagrave le travail lutilisateur peut ouvrir le fichier quil souhaite

VI-C - Code source

chapitre6zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 22 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VII - Interlude

Avant daller plus loin dans lameacutelioration de linterface de notre eacutediteur il est neacutecessaire de modifier sonfonctionnement interne (ne vous inquieacutetez je nai pas dit chambouler) en effet souvenez-vous dans lintroduction jaieacutevoqueacute la possibiliteacutes douvrir plusieurs documents gracircce agrave un systegraveme donglets Pour cela il faut sauvegarder lesproprieacuteteacutes de chaque document ouvert Pris agrave temps ce genre de modification nest pas trop lourde mais si nousattendons cela risque de devenir un vrai casse tecircte

Pour cela nous allons utiliser une structure de donneacutee pour chaque document ouvert qui devra garder en meacutemoirele chemin complet du fichier (ou NULL si le document nest pas encore sauvegarder) sil agrave eacutetait modifier depuis laderniegravere sauvegarde et le GtkTextView qui sert agrave son affichage Voici donc la structure qui va nous servir

documenthtypedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

Sachant que nous serons ameneacute agrave stocker plusieurs occurrences de cette structure il serait bon de reacutefleacutechir degravesmaintenant agrave la structure de donneacutee agrave utiliser pour les stocker La premiegravere ideacutee qui vient agrave lesprit est un tableaualloueacute dynamiquement cependant lutilisateur peut souhaiter fermer un document qui se trouve au milieu on estalors obligeacute de deacutecaler toutes les cellules en amont Dans ce cas il parait naturel dutiliser une liste chaicircneacutee Parchance la glib propose une bibliothegraveque de gestion des listes chaicircneacutees cela nous fera gagner du temps le momentvenu Pour linstant on se contente de creacuteer une structure de donneacutees qui contiendra tous les documents ouverts(stockeacutee dans une GList) et un pointeur sur le document actif (actuellement comme nous navons quun documentouvert en mecircme temps on manipulera uniquement ce pointeur)

documenthtypedef struct GList tous document_t actif docs_t

Maintenant se pose le problegraveme de savoir comment transmettre cette structure On pourrait se servir du paramegravetreuser_data preacutesent dans toutes les fonctions callback mais certaines fonctions utilise deacutejagrave ce paramegravetre (la fonctioncb_open par exemple) il faudrait creacuteer un champs suppleacutementaire dans notre structure documents_s Une solutionplus simple est de creacuteer une variable globale agrave lensemble du programme Ceux qui passe reacuteguliegraverement sur le forumC savent que cest fortement deacuteconseilleacute mais ici nous nous trouvons dans lune des rares exceptions agrave la regravegle Detoute faccedilon cela revient au mecircme que de passer ladresse de notre structure agrave toutes les fonctions callback Nousdeacutefinissons donc un nouveau fichier den-tecircte

documenthifndef H_DOCUMENTdefine H_DOCUMENT

include ltgtkgtkhgt

typedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 23 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

documenthtypedef struct GList tous document_t actif docs_t

extern docs_t docs

endif not H_DOCUMENT

Et dans le fichier mainc

maincinclude documenth

docs_t docs = NULL NULL

Pour linstant la seule fonction qui modifie leacutetat dun document est la fonction open_file il faut donc inclure documenthdans callbackc et modifier leacutegegraverement la fonction pour enregistrer le document ouvert

callbackc if (g_file_get_contents (file_name ampcontents NULL NULL)) Pour linstant il faut allouer la memoire par la suite on modifira simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = g_strdup (file_name) Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = p_text_view Le document vient detre ouvert il nest donc pas modifie docsactif-gtsauve = TRUE

Ne soyez pas choqueacute si je ne teste pas le retour de la fonction g_malloc pour veacuterifier quilnest pas NULL En effet cette derniegravere met fin agrave lapplication si lallocation eacutechoue

VII-A - Code source

chapitre7zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 24 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VIII - Sauvegarder les modification

VIII-A - Aperccedilu

Cliquez pour agrandir

VIII-B - Enregistrer

Avant de pouvoir sauvegarder un document il faut quil soit modifieacute Comment savoir que le contenu du fichier a eacuteteacutemodifier Gracircce au signal changed du GtkTextBuffer que nous interceptons gracircce agrave la fonction cb_modifie

mainc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (p_text_view)) g_signal_connect (G_OBJECT (p_text_buffer) changed G_CALLBACK (cb_modifie) NULL)

Cette derniegravere modifie simplement le champ sauve du document

callbackcvoid cb_modifie (GtkWidget p_widget gpointer user_data) if (docsactif) docsactif-gtsauve = FALSE

Pour la sauvegarde il faut distinguer deux cas soit il sagit de la premiegravere sauvegarde du fichier il faut alors demanderle nom du fichier agrave lutilisateur (cela ressemble fortement agrave louverture dun fichier) soit le fichier est deacutejagrave preacutesent surle disque il suffit de remplacer son contenu par celui du GtkTextViewer Nous avons convenu quun fichier qui neacutetaitpas encore enregistreacute avait sa proprieacuteteacute chemin agrave NULL

Bien sucircr cela na lieu que si un fichier est ouvert et quil a eacuteteacute modifieacute depuis sa derniegravere sauvegarde

callbackcvoid cb_save (GtkWidget p_widget gpointer user_data) if (docsactif) if (docsactif-gtsauve) Le fichier na pas encore ete enregistre if (docsactif-gtchemin) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Sauvegarder le fichier NULL GTK_FILE_CHOOSER_ACTION_SAVE GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_SAVE GTK_RESPONSE_ACCEPT NULL) if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 25 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc docsactif-gtchemin = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) gtk_widget_destroy (p_dialog) Soit le fichier a deja ete enregistre soit lutilisateur vient de nous fournir son nouvel enplacement on peut donc lenregistrer if (docsactif-gtchemin) else print_warning (Aucun document ouvert)

Il nous reste plus quagrave reacutecupeacuterer le contenu du GtkTextViewer et le copier dans le fichier chemin sans oublier dereconvertir le texte dans le codage local

callbackc FILE fichier = NULL

fichier = fopen (docsactif-gtchemin w) if (fichier) gchar contents = NULL gchar locale = NULL GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) contents = gtk_text_buffer_get_text (p_text_buffer ampstart ampend FALSE) locale = g_locale_from_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL fprintf (fichier s locale) g_free (locale) locale = NULL fclose (fichier) fichier = NULL docsactif-gtsauve = TRUE else print_warning (Impossible de sauvegarder le fichier s docsactif-gtchemin)

Le dernier paramegravetre de la fonction gtk_text_buffer_get_text est mis agrave FALSE car nous ne voulons pas enregistrerles caractegraveres invisibles preacutesent dans le GtkTextBuffer Ces caractegraveres servent agrave mettre en forme le texte (taillecouleur) nous pourrions creacuteer un nouveau format de fichier pour enregistrer la mise en forme

VIII-C - Enregistrer sous

Pour enregistrer notre document sous un autre nom il suffit de faire croire agrave cb_save que le document na pas encoreeacutetait enregistreacute tout simplement en changeant chemin agrave NULL et sauve agrave FALSE

callbackcvoid cb_saveas (GtkWidget p_widget gpointer user_data)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 26 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (docsactif) document_t tmp = docsactif

docsactif-gtchemin = NULL docsactif-gtsauve = FALSE cb_save (p_widget user_data) if (docsactif-gtsauve) (docsactif) = tmp else print_warning (Aucun document ouvert)

Il ne faut pas oublier que lutilisateur peut annuler lenregistrement de ce fait nous sauvegardons leacutetat du documentet si la sauvegarde na pas eu lieu on le restaure

VIII-D - Code source

chapitre8zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 27 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IX - Creacuteer un nouveau document

IX-A - Aperccedilu

Cliquez pour agrandir

IX-B - Nouveau fichier

Maintenant que lutilisateur peut ouvrir et fermer un fichier il est inteacuteressant de lui donner la possibiliteacute den creacuteerun nouveau Je ne reviens pas sur la creacuteation du bouton (ccedila devrait deacutejagrave ecirctre fait D) passons directement agrave lafonction cb_new

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) Pour linstant il faut allouer la memoire par la suite on modifiera simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = NULL Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = GTK_TEXT_VIEW (user_data) Le document vient detre creer il nest donc pas modifie docsactif-gtsauve = TRUE gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Je ne sais pas vous mais pour ma part jai fait un copiercoller de la fonction open_file Et oui ouvrir un document peutse reacutesumer agrave creacuteer un document vide puis remplir le GtkTextView avec le fichier souhaiteacute On peut donc simplifiernotre fonction open_file ainsi

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

cb_new (NULL p_text_view) gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE) p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1) Nous sommes obliges de remetre sauve a TRUE car linsertion du contenu du fichier dans le GtkTextView a appele cb_modfie docsactif-gtsauve = TRUE else print_warning (Impossible douvrir le fichier sn file_name)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 28 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc

Cest beau la factorisation du code Par contre nous sommes obligeacutes de remettre sauve agrave TRUE car nous avonsmodifieacute le GtkTextBuffer

IX-C - Code source

chapitre9zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 29 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

X - Fermer

X-A - Aperccedilu

Cliquez pour agrandir

X-B - Fermer un fichier

Maintenant que nous allouons de la meacutemoire il faut la libeacuterer agrave un endroit Logiquement cela va ecirctre fait agrave la fermeturedu document en guise dexercice je vous laisse creacuteer le bouton dans notre boicircte agrave bouton

Allez je vous aide le stock id correspondant est GTK_STOCK_CLOSE

Voilagrave maintenant si tout cest bien passeacute vous devriez ecirctre arriveacute dans le fichier callbackc avec quelque choseressemblant agrave

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data)

Lorsque lon ferme un document il faut vider le GtkTextView (avec les onglets on se contentera de le supprimer)pour cela il faut reacutecupeacuterer le deacutebut et la fin du GtkTextBuffer et demander agrave GTK+ de supprimer tout ce qui ce trouveentre les deux iteacuterateurs

callbackc Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) gtk_text_buffer_delete (p_text_buffer ampstart ampend) else print_warning (Aucun document ouvert)

Bien sucircr il ne faut pas oublier de libeacuterer la meacutemoire

callbackc g_free (docsactif-gtchemin) docsactif-gtchemin = NULL docsactif-gtp_text_view = NULL g_free (docsactif) docsactif = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 30 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour symboliser la fermeture dun document nous deacutesactivons le GtkTextView lors de la fermeture (ne pas oublierde le faire aussi dans mainc)

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) FALSE)

Et nous le reacuteactivons lors de louverture si celle si reacuteussie

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Lorsque lutilisateur quitte lapplication il faut bien sucircr fermer le document sil y en a un ouvert

void cb_quit (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data) gtk_main_quit()

Et aussi lorsquil creacuteeacute un nouveau document (et par conseacutequent lorsquil ouvre un fichier puisque lon fait appel agravecb_new)

void cb_new (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data)

X-C - Enregistrer avant de fermer

Si le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde geacuteneacuteralement le programme le signale agrave lutilisateur etlui propose de sauvegarder ou dannuler la fermeture Pour se faire nous devons modifier la fonction cb_close avantde fermer le document nous allons afficher une boicircte de dialogue

Pour creacuteer une boicircte de dialogue simplement il existe la classe GtkDialog et comme nous avons besoin de boutons(pour que lutilisateur fasse son choix) nous allons creacuteer notre boicircte avec la fonction

GtkWidget gtk_dialog_new_with_buttons (const gchar title GtkWindow parent GtkDialogFlags flags const gchar first_button_text )

Nous retrouvons les mecircmes options que pour le GtkFileChooserDialog mis agrave part option du type GtkDialogFlags

typedef enum GTK_DIALOG_MODAL = 1 ltlt 0 appel gtk_window_set_modal (win TRUE) GTK_DIALOG_DESTROY_WITH_PARENT = 1 ltlt 1 appel gtk_window_set_destroy_with_parent () GTK_DIALOG_NO_SEPARATOR = 1 ltlt 2 Pas de barre de separation au dessus des boutons GtkDialogFlags

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 31 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Nous nous contenterons de rendre notre fenecirctre modale (7)

Pour avoir accegraves agrave notre fenecirctre principale nous ajoutons un champs p_main_window agrave notre structure globaledocs_t que nous initialisons dans la fonction main

mainc docsp_main_window = GTK_WINDOW (p_window)

Il nous reste plus qua creacuteer notre boicircte de dialogue avec trois boutons Oui Non Annuler

callbackc if (docsactif-gtsauve) GtkWidget p_dialog = NULL

p_dialog = gtk_dialog_new_with_buttons (Sauvegarder docsp_main_window GTK_DIALOG_MODAL GTK_STOCK_YES GTK_RESPONSE_YES GTK_STOCK_NO GTK_RESPONSE_NO GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL NULL)

Nous obtenons donc une structure de type GtkDialog

typedef struct GtkWidget vbox GtkWidget action_area GtkDialog

Nous remarquons que cette structure contient deux membres qui permettent dacceacuteder agrave une GtkBox ougrave nous allonsajouter le contenu de la fenecirctre et agrave la partie contenant les boutons

Ensuite la construction de la fenecirctre est identique agrave celle de la fenecirctre principale ici nous nous contenterons dajouterun GtkLabel

callbackc GtkWidget p_label = NULL p_label = gtk_label_new (Voulez-vous sauvegarder les modifications ) gtk_box_pack_start (GTK_BOX (GTK_DIALOG (p_dialog)-gtvbox) p_label TRUE TRUE 0)

Une fois notre fenecirctre precircte il suffit de faire appel agrave la fonction gtk_dialog_run qui va afficher notre GtkDialog et nousretourner le reacuteponse id correspondant au bouton cliqueacute par lutilisateur

callbackc switch (gtk_dialog_run (GTK_DIALOG (p_dialog))) case GTK_RESPONSE_YES cb_save (p_widget user_data) break case GTK_RESPONSE_NO break case GTK_RESPONSE_CANCEL gtk_widget_destroy (p_dialog) return break

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 32 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc gtk_widget_destroy (p_dialog)

Si lutilisateur clique sur non on ne fait rien (le document sera simplement fermeacute) sur oui on enregistre avant defermer et pour finir sil annule on quitte la fonction

X-D - Code source

chapitre10zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 33 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XI - Les barres de deacutefilement

XI-A - Aperccedilu

Cliquez pour agrandir

XI-B - Ajouter des barres de deacutefilement

Apregraves le dernier chapitre quelque peu laborieux voici une partie plus simple mais qui va rendre notre applicationplus pratique En effet si vous avez essayeacute douvrir un fichier de grande taille vous avez pu remarquer que pourpouvoir lire la fin du fichier il fallait utiliser les touches du clavier pas tregraves convivial

Pour rendre la navigation plus aiseacutee on utilise des barres de deacutefilement

mainc GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_scrolled_window TRUE TRUE 0)

Creation de la zone de texte gtk_container_add (GTK_CONTAINER (p_scrolled_window) p_text_view)

Le constructeur de notre GtkScrolledWindow prend en argument deux GtkAdjustment qui permettent de deacutefinirdiffeacuterentes proprieacuteteacutes de la barre de deacutefilement (taille dune page la position de deacutepart) nous laissons GTK+ faireen passant NULL

Cest un bon deacutebut mais estheacutetiquement on peut faire mieux mecircme sil nest pas utile davoir une barre de deacutefilementelle est quand mecircme afficheacutee On peut demander agrave GTK+ de les afficher que si cela est neacutecessaire

mainc gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC)

En fait nous avons de la chance car la classe GtkTextView fait partie des widget qui supporte de faccedilon native les barresde deacutefilement Comment le savoir Ce genre de widget possegravede une ou deux proprieacuteteacutes de type GtkAdjustment (unepour la barre verticale lautre pour la barre horizontale) Actuellement seulement trois classes en sont capables lesGtkTextView les GtkTreeView et les GtkLayout

Comment faire pour les autres widgets Il faut passer par une classe adaptateur GtkViewport afin de creacuteer lesGtkAdjustment

XI-C - Code source

chapitre11zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 34 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XII - Les menus

XII-A - Aperccedilu

Cliquez pour agrandir

XII-B - Creacuteation du menu

Pour simplifier nous avons utiliseacute des boutons pour permettre agrave lutilisateur de creacuteer un document ouvrir un fichierMais il est plus courant dutiliser un menu pour afficher ces options GTK+ propose trois maniegraveres de creacuteer un menu

bull GtkItemFactory cette meacutethode est obsolegravete depuis la version 24 de GTK+

bull GtkUIManager cest ce quon appel une usine agrave gaz pour en savoir plus vous pouvez vous reporter aututoriel Utilisation de GtkUIManager

bull GtkMenu cest ce widget que nous allons eacutetudier il permet de creacuteer un menu manuellement (agrave lopposeacute deGtkUIManager)

Un menu selon GTK+ est composeacute de plusieurs eacuteleacutements

bull GtkMenuBar la barre de menu elle-mecircme

bull GtkMenu la partie deacuteroulante qui contient les diffeacuterents eacuteleacutements

bull GtkMenuItem cest sur ce widget que lutilisateur clique pour lancer une action

Pour commencer faisons linventaire de ce que nous avons besoin

bull Un GtkMenuBar qui sert de base au menu

bull Un GtkMenu pour commencer nous nous aurons dun menu Fichier

bull Six GtkMenuItem pour remplacer nos six boutons

Commenccedilons par la creacuteation du menu nous mettons ce code dans un nouveau fichier dont seul la fonction menu_newsera accessible

menucGtkMenuBar menu_new (gpointer user_data) GtkWidget p_menu_bar = NULL

p_menu_bar = gtk_menu_bar_new () return GTK_MENU_BAR (p_menu_bar)

Le paramegravetre user_data nous servira lors de la connexion des callbacks (nous en avons besoin pour les fonctionscb_new et cb_open)

Ensuite nous allons creacuteer notre sous menu Fichier

menuc Menu Fichier

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 35 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

menuc GtkWidget p_menu = NULL GtkWidget p_menu_item = NULL

p_menu = gtk_menu_new () p_menu_item = gtk_menu_item_new_with_mnemonic (_Fichier) gtk_menu_item_set_submenu (GTK_MENU_ITEM (p_menu_item) p_menu) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu_bar) p_menu_item) return GTK_MENU_BAR (p_menu_bar)

Un sous menu est en fait un GtkMenuItem auquel on assigne un GtkMenu Il faut bien sucircr terminer la creacuteation dusous-menu en lajoutant agrave la barre de menu

Pour finir nous creacuteons les eacuteleacutements du menu les GtkItemMenu Il existe plusieurs types deacuteleacutements (comparableaux diffeacuterents types de bouton) pour commencer nous nutiliserons que le type de base Comme cette opeacuteration estreacutepeacutetitive nous allons creacuteer une fonction pour le faire

menucstatic void menu_item_new (GtkMenu p_menu const gchar title GCallback callback gpointer user_data) GtkWidget p_menu_item = NULL

p_menu_item = gtk_menu_item_new_with_mnemonic (title) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu) p_menu_item) g_signal_connect (G_OBJECT (p_menu_item) activate callback user_data)

Pour permettre agrave lutilisateur dacceacuteder aux diffeacuterents eacuteleacutements du menu agrave laide de la touche ltAltgt nous utilisonsdes mneacutemoniques par exemple pour quitter leacutediteur il suffit de faite Alt+F puis Q Et voici le code pour creacuteer nossix eacuteleacutements du menu

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau G_CALLBACK (cb_new) user_data) menu_item_new (GTK_MENU (p_menu) _Ouvrir G_CALLBACK (cb_open) user_data) menu_item_new (GTK_MENU (p_menu) _Enregistrer G_CALLBACK (cb_save) user_data) menu_item_new (GTK_MENU (p_menu) Enregistrer _sous G_CALLBACK (cb_saveas) user_data) menu_item_new (GTK_MENU (p_menu) _Fermer G_CALLBACK (cb_close) user_data) menu_item_new (GTK_MENU (p_menu) _Quitter G_CALLBACK (cb_quit) user_data)

Voilagrave notre menu est creacuteeacute il nous reste plus quagrave linteacutegrer agrave notre fenecirctre

mainc gtk_box_pack_start (GTK_BOX (p_main_box) GTK_WIDGET (menu_new (p_text_view)) FALSE FALSE 0)

Le problegraveme cest que nous avons besoin de passer le GtkTextView lors de la creacuteation du menu (qui est utiliseacute par lesfonctions cb_new et cb_open) or celui-ci est creacuteeacute apregraves le menu (puisque nous creacuteons les widgets dans lordre ougrave ilfaut les inteacutegrer agrave linterface (8) ) nous devons creacuteer le GtkTextView (seul lappel agrave gtk_text_view_new est deacuteplaceacute)

XII-C - Code source

chapitre12zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 36 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIII - Les barres doutils

XIII-A - Aperccedilu

Cliquez pour agrandir

XIII-B - Creacuteation dune barre doutils

La creacuteation dune barre doutils ressemble fort agrave celle dun menu en plus simple puisquil ny a pas de sous menu on creacutee notre barre doutils (gtk_toolbar_new) puis les eacuteleacutements de la barre pour cela on utilise des boutons(gtk_tool_button_new_from_stock) que lon inseacutere dans la barre (gtk_toolbar_insert) Pas conseacutequent notre fichierbarreoutilsc ressemble agrave menuc

barreoutilscinclude ltgtkgtkhgtinclude callbackhinclude barreoutilsh

static void toolbar_item_new (GtkToolbar const gchar GCallback gpointer)

GtkToolbar toolbar_new (gpointer user_data) GtkWidget p_toolbar = NULL

p_toolbar = gtk_toolbar_new () toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_NEW G_CALLBACK (cb_new) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_OPEN G_CALLBACK (cb_open) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE G_CALLBACK (cb_save) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE_AS G_CALLBACK (cb_saveas) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_CLOSE G_CALLBACK (cb_close) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_QUIT G_CALLBACK (cb_quit) user_data) return GTK_TOOLBAR (p_toolbar)

static void toolbar_item_new (GtkToolbar p_toolbar const gchar stock_id GCallback callback gpointer user_data) GtkToolItem p_tool_item = NULL

p_tool_item = gtk_tool_button_new_from_stock (stock_id) g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data) gtk_toolbar_insert (p_toolbar p_tool_item -1)

Le code nest pas complet car lorsque jexeacutecute le programme GTK+ affiche en plus des icocircnes le texte sous lesboutons Pour modifier cela il suffit dajouter une ligne de code

barreoutilsc gtk_toolbar_set_style (GTK_TOOLBAR (p_toolbar) GTK_TOOLBAR_ICONS)

Pourquoi gtk_tool_button_new_from_stock retourne un GtkToolItem et non un GtkWidgetcomme nous avons eacuteteacute habitueacute jusquagrave preacutesent Il sagit dune bizarrerie de GTK+ dontje ne connais pas la raison

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 37 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour anticiper un changement dinterface (dans GTK+ 30 peut ecirctre ) nous aurions pueacutecrire

Gtkwidget p_tool_item = NULL

p_tool_item = GTK_WIDGET (gtk_tool_button_new_from_stock (stock_id))g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data)gtk_toolbar_insert (p_toolbar GTK_TOOL_ITEM (p_tool_item) -1)

XIII-C - Code source

chapitre13zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 38 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIV - Les racourcis clavier

XIV-A - Aperccedilu

Cliquez pour agrandir

XIV-B - Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mneacutemoniques ces derniers permettent dacceacuteder agrave un eacuteleacutementseacutequentiellement alors que les raccourcis appellent une fonction si lutilisateur appuie simultaneacutement sur une ouplusieurs touches (geacuteneacuteralement de la forme ltModificateurgtTouche ougrave Modificateur repreacutesente les touches ShiftAlt et Control) Ce raccourci peut ecirctre attacheacute agrave un eacuteleacutement du menu mais ceci nest pas obligatoire

Les raccourcis sont regroupeacutes en groupe dans un GtkAccelGroup quil faut commencer par creacuteer

raccourciscinclude ltgtkgtkhgtinclude callbackhinclude raccourcish

GtkAccelGroup accel_group_new (gpointer user_data) GtkAccelGroup p_accel_group = NULL

p_accel_group = gtk_accel_group_new () return p_accel_group

Vous commencez agrave avoir lhabitude de cette organisation nous allons donc creacuteer une fonction qui va se chargerdajouter un raccourci au groupe

raccourciscstatic void accelerator_new (GtkAccelGroup p_accel_group const gchar accelerator const gchar accel_path GCallback callback gpointer user_data) guint key GdkModifierType mods GClosure closure = NULL

gtk_accelerator_parse (accelerator ampkey ampmods) closure = g_cclosure_new (callback user_data NULL) gtk_accel_group_connect (p_accel_group key mods GTK_ACCEL_VISIBLE closure) gtk_accel_map_add_entry (accel_path key mods)

La fonction gtk_accelerator_parse permet de deacutecomposer une chaicircne de caractegraveres de la forme ltControlgtF1 ouencore ltAltgtA en numeacutero de touche et modificateur

En plus des touches pour creacuteer un raccourci clavier nous avons besoin dune fonction agrave appeler lorsque lutilisateurappuie sur les touches speacutecifieacutees gtk_accel_group_connect attend une fonction du type GClosure regardons ladocumentation de gobject pour savoir agrave quoi cela correspond

typedef struct

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 17 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

bull g_return_if_fail est une macro qui peut ecirctre compareacutee agrave assert sauf quelle se contente de sortir de la fonctionsi lexpression passeacutee en paramegravetre est fausse Cest une meacutethode pratique pour veacuterifier la validiteacute desparamegravetres (si la fonction doit retourne une valeur utiliseacute plutocirct g_return_val_if_fail qui prend un secondparamegravetre la valeur agrave retourner)

bull Ensuite on essaie de reacutecupeacuterer le contenu de notre fichier

bull Si cela eacutechoue nous le signalons agrave lutilisateur agrave laide de la fonction print_warning

bull Le type gchar est une redeacutefinition du type char par la glib (il en va de mecircme pour tous les autres types du C)privileacutegiez ces types lorsque vous utilisez des fonctions de cette bibliothegraveques

Mais quest-ce donc cette fonction print_warning Cest une fonction que nous allons creacuteer semblable agrave printf quisignalera agrave lutilisateur quune erreur non critique est survenue Comme nous navons pas encore abordeacute les boicirctesde dialogue pour afficher un message il sagira pour linstant dune simple redeacutefinition de printf Pendant que noussommes dans laffichage des messages nous allons aussi creacuteer deux fonctions print_info et print_error qui vontrespectivement afficher un message dinformation et un message derreur critique (ce qui entraicircne la terminaison duprogramme) tout ceci dans un nouveau fichier errorc

errorhifndef H_ERRORdefine H_ERROR

void print_info (char )void print_warning (char )void print_error (char )

endif not H_ERROR

errorcinclude ltstdarghgtinclude ltstdiohgtinclude ltstdlibhgtinclude errorh

void print_info (char format ) va_list va

va_start (va format) printf (Information ) vprintf (format va) printf (n)

void print_warning (char format ) va_list va

va_start (va format) fprintf (stderr Erreur ) vfprintf (stderr format va) fprintf (stderr n)

void print_error (char format ) va_list va

va_start (va format) fprintf (stderr Erreur fatale ) vfprintf (stderr format va) fprintf (stderr n) exit (EXIT_FAILURE)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 18 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

Pour en finir avec louverture dun fichier il nous reste agrave copier contents dans le GtkTextView En fait le GtkTextViewne gegravere que la forme pour modifier le contenu il faut passer par les GtkTextBuffer Commenccedilons donc par reacutecupeacutererce fameux GtkTextBuffer

callbackc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (p_text_view)

Et pour finir on utilise la fonction

void gtk_text_buffer_insert (GtkTextBuffer buffer GtkTextIter iter const gchar text gint len)

Reacutecapitulons buffer est le GtkTextBuffer que lon vient de reacutecupeacuterer text cest le texte agrave afficher et len la taille dece dernier (ou -1 sil sagit dune chaicircne de caractegraveres au sens du langage C)

Mais quest-ce donc ce GtkTextIter On peut voir cela comme un curseur virtuel qui indique la position agrave laquelleeffectuer linsertion de texte dans le GtkTextBuffer (5) Allons voir ce que la documentation peut nous apprendreagrave leur sujet (6)

typedef struct GtkTextIter is an opaque datatype ignore all these fields Initialize the iter with gtk_text_buffer_get_iter_ functions GtkTextIter

Voilagrave on a notre solution suffit de rechercher les fonctions commenccedilant par gtk_text_buffer_get_iter_ voici la liste

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)

La fonction gtk_text_buffer_get_iter_at_line fait parfaitement laffaire

callbackc GtkTextIter iter

gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1)

Cependant si vous ne voulez pas avoir de problegravemes avec le codage des caractegraveres il vaut mieux convertir le codagelocal vers utf8 Voici le reacutesultat final

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 19 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gchar utf8 = NULL GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_text_buffer_insert (p_text_buffer ampiter utf8 -1) g_free (utf8) utf8 = NULL

V-D - La petite touche finale

Pour finir cette laborieuse partie sur une petite touche estheacutetique nous allons demander agrave GTK+ de nous lancerlapplication en plein eacutecran Pour se faire il suffit dajouter lors de la creacuteation de la fenecirctre principale

maincgtk_window_maximize (GTK_WINDOW (p_window))

On peut mecircme se permettre une pointe dexcentriciteacute en modifiant le titre de notre fenecirctre

maincgtk_window_set_title (GTK_WINDOW (p_window) Editeur de texte en GTK+)

V-E - Code source

chapitre5zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 20 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VI - Choisir un fichier

VI-A - Aperccedilu

Cliquez pour agrandir

VI-B - Utilisation dun GtkFileChooserFile

Jusquagrave preacutesent lutilisateur navait pas le choix quant au fichier agrave ouvrir heureusement GTK+ vient agrave notre aide gracircceau widget GtkFileChooserFile qui est tout simplement une boicircte de dialogue qui propose agrave lutilisateur de seacutelectionnerun fichier dans son arborescence disque

Commenccedilons par creacuteer notre boicircte de dialogue dans la fonction cb_open

callbackcvoid cb_open (GtkWidget p_widget gpointer user_data) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Ouvrir un fichier NULL GTK_FILE_CHOOSER_ACTION_OPEN GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_OPEN GTK_RESPONSE_ACCEPT NULL)

Cette fonction neacutecessite le titre de la boicircte de dialogue une fenecirctre parente le type daction (ici on souhaite ouvrir unfichier GTK+ autorisera lutilisateur agrave seacutelectionner uniquement les fichiers existants) Pour finir il sagit dun couple devaleurs GTK_STOCK_ITEMGTK_STOCK_RESPONSE qui permet de creacuteer un bouton utilisant le stock ID speacutecifieacuteet lorsque celui-ci est cliqueacute la fonction servant agrave lancer la boicircte de dialogue retournera le reacuteponse ID correspondantIl existe une seacuterie de valeurs deacutefinies par GTK+ quil est conseilleacute dutiliser

typedef enum GTK returns this if a response widget has no response_id or if the dialog gets programmatically hidden or destroyed GTK_RESPONSE_NONE = -1

GTK wont return these unless you pass them in as the response for an action widget They are for your convenience GTK_RESPONSE_REJECT = -2 GTK_RESPONSE_ACCEPT = -3

If the dialog is deleted GTK_RESPONSE_DELETE_EVENT = -4

These are returned from GTK dialogs and you can also use them yourself if you like GTK_RESPONSE_OK = -5 GTK_RESPONSE_CANCEL = -6 GTK_RESPONSE_CLOSE = -7 GTK_RESPONSE_YES = -8

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 21 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GTK_RESPONSE_NO = -9 GTK_RESPONSE_APPLY = -10 GTK_RESPONSE_HELP = -11 GtkResponseType

Nous indiquons la fin des couples stock idreacuteponse id avec la valeur NULL

Une fois la boicircte de dialogue creacuteee on demande agrave GTK+ de lafficher gracircce agrave la fonction gtk_dialog_run puis onreacutecupegravere sa valeur de retour qui correspond au bouton cliqueacute par lutilisateur

callbackc if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

Ici ce qui nous inteacuteresse cest lorsque que lutilisateur clique sur le bouton ouvrir (donc gtk_dialog_run renvoieGTK_RESPONSE_ACCEPT) dans ce cas il nous suffit de reacutecupeacuterer le nom du fichier seacutelectionneacute puis de louvrir

callbackc gchar file_name = NULL

file_name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) open_file (file_name GTK_TEXT_VIEW (user_data)) g_free (file_name) file_name = NULL

Pour finir dans tous les cas on noublie pas de deacutetruire la boicircte de dialogue

callbackc gtk_widget_destroy (p_dialog)

Et voilagrave le travail lutilisateur peut ouvrir le fichier quil souhaite

VI-C - Code source

chapitre6zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 22 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VII - Interlude

Avant daller plus loin dans lameacutelioration de linterface de notre eacutediteur il est neacutecessaire de modifier sonfonctionnement interne (ne vous inquieacutetez je nai pas dit chambouler) en effet souvenez-vous dans lintroduction jaieacutevoqueacute la possibiliteacutes douvrir plusieurs documents gracircce agrave un systegraveme donglets Pour cela il faut sauvegarder lesproprieacuteteacutes de chaque document ouvert Pris agrave temps ce genre de modification nest pas trop lourde mais si nousattendons cela risque de devenir un vrai casse tecircte

Pour cela nous allons utiliser une structure de donneacutee pour chaque document ouvert qui devra garder en meacutemoirele chemin complet du fichier (ou NULL si le document nest pas encore sauvegarder) sil agrave eacutetait modifier depuis laderniegravere sauvegarde et le GtkTextView qui sert agrave son affichage Voici donc la structure qui va nous servir

documenthtypedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

Sachant que nous serons ameneacute agrave stocker plusieurs occurrences de cette structure il serait bon de reacutefleacutechir degravesmaintenant agrave la structure de donneacutee agrave utiliser pour les stocker La premiegravere ideacutee qui vient agrave lesprit est un tableaualloueacute dynamiquement cependant lutilisateur peut souhaiter fermer un document qui se trouve au milieu on estalors obligeacute de deacutecaler toutes les cellules en amont Dans ce cas il parait naturel dutiliser une liste chaicircneacutee Parchance la glib propose une bibliothegraveque de gestion des listes chaicircneacutees cela nous fera gagner du temps le momentvenu Pour linstant on se contente de creacuteer une structure de donneacutees qui contiendra tous les documents ouverts(stockeacutee dans une GList) et un pointeur sur le document actif (actuellement comme nous navons quun documentouvert en mecircme temps on manipulera uniquement ce pointeur)

documenthtypedef struct GList tous document_t actif docs_t

Maintenant se pose le problegraveme de savoir comment transmettre cette structure On pourrait se servir du paramegravetreuser_data preacutesent dans toutes les fonctions callback mais certaines fonctions utilise deacutejagrave ce paramegravetre (la fonctioncb_open par exemple) il faudrait creacuteer un champs suppleacutementaire dans notre structure documents_s Une solutionplus simple est de creacuteer une variable globale agrave lensemble du programme Ceux qui passe reacuteguliegraverement sur le forumC savent que cest fortement deacuteconseilleacute mais ici nous nous trouvons dans lune des rares exceptions agrave la regravegle Detoute faccedilon cela revient au mecircme que de passer ladresse de notre structure agrave toutes les fonctions callback Nousdeacutefinissons donc un nouveau fichier den-tecircte

documenthifndef H_DOCUMENTdefine H_DOCUMENT

include ltgtkgtkhgt

typedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 23 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

documenthtypedef struct GList tous document_t actif docs_t

extern docs_t docs

endif not H_DOCUMENT

Et dans le fichier mainc

maincinclude documenth

docs_t docs = NULL NULL

Pour linstant la seule fonction qui modifie leacutetat dun document est la fonction open_file il faut donc inclure documenthdans callbackc et modifier leacutegegraverement la fonction pour enregistrer le document ouvert

callbackc if (g_file_get_contents (file_name ampcontents NULL NULL)) Pour linstant il faut allouer la memoire par la suite on modifira simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = g_strdup (file_name) Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = p_text_view Le document vient detre ouvert il nest donc pas modifie docsactif-gtsauve = TRUE

Ne soyez pas choqueacute si je ne teste pas le retour de la fonction g_malloc pour veacuterifier quilnest pas NULL En effet cette derniegravere met fin agrave lapplication si lallocation eacutechoue

VII-A - Code source

chapitre7zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 24 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VIII - Sauvegarder les modification

VIII-A - Aperccedilu

Cliquez pour agrandir

VIII-B - Enregistrer

Avant de pouvoir sauvegarder un document il faut quil soit modifieacute Comment savoir que le contenu du fichier a eacuteteacutemodifier Gracircce au signal changed du GtkTextBuffer que nous interceptons gracircce agrave la fonction cb_modifie

mainc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (p_text_view)) g_signal_connect (G_OBJECT (p_text_buffer) changed G_CALLBACK (cb_modifie) NULL)

Cette derniegravere modifie simplement le champ sauve du document

callbackcvoid cb_modifie (GtkWidget p_widget gpointer user_data) if (docsactif) docsactif-gtsauve = FALSE

Pour la sauvegarde il faut distinguer deux cas soit il sagit de la premiegravere sauvegarde du fichier il faut alors demanderle nom du fichier agrave lutilisateur (cela ressemble fortement agrave louverture dun fichier) soit le fichier est deacutejagrave preacutesent surle disque il suffit de remplacer son contenu par celui du GtkTextViewer Nous avons convenu quun fichier qui neacutetaitpas encore enregistreacute avait sa proprieacuteteacute chemin agrave NULL

Bien sucircr cela na lieu que si un fichier est ouvert et quil a eacuteteacute modifieacute depuis sa derniegravere sauvegarde

callbackcvoid cb_save (GtkWidget p_widget gpointer user_data) if (docsactif) if (docsactif-gtsauve) Le fichier na pas encore ete enregistre if (docsactif-gtchemin) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Sauvegarder le fichier NULL GTK_FILE_CHOOSER_ACTION_SAVE GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_SAVE GTK_RESPONSE_ACCEPT NULL) if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 25 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc docsactif-gtchemin = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) gtk_widget_destroy (p_dialog) Soit le fichier a deja ete enregistre soit lutilisateur vient de nous fournir son nouvel enplacement on peut donc lenregistrer if (docsactif-gtchemin) else print_warning (Aucun document ouvert)

Il nous reste plus quagrave reacutecupeacuterer le contenu du GtkTextViewer et le copier dans le fichier chemin sans oublier dereconvertir le texte dans le codage local

callbackc FILE fichier = NULL

fichier = fopen (docsactif-gtchemin w) if (fichier) gchar contents = NULL gchar locale = NULL GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) contents = gtk_text_buffer_get_text (p_text_buffer ampstart ampend FALSE) locale = g_locale_from_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL fprintf (fichier s locale) g_free (locale) locale = NULL fclose (fichier) fichier = NULL docsactif-gtsauve = TRUE else print_warning (Impossible de sauvegarder le fichier s docsactif-gtchemin)

Le dernier paramegravetre de la fonction gtk_text_buffer_get_text est mis agrave FALSE car nous ne voulons pas enregistrerles caractegraveres invisibles preacutesent dans le GtkTextBuffer Ces caractegraveres servent agrave mettre en forme le texte (taillecouleur) nous pourrions creacuteer un nouveau format de fichier pour enregistrer la mise en forme

VIII-C - Enregistrer sous

Pour enregistrer notre document sous un autre nom il suffit de faire croire agrave cb_save que le document na pas encoreeacutetait enregistreacute tout simplement en changeant chemin agrave NULL et sauve agrave FALSE

callbackcvoid cb_saveas (GtkWidget p_widget gpointer user_data)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 26 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (docsactif) document_t tmp = docsactif

docsactif-gtchemin = NULL docsactif-gtsauve = FALSE cb_save (p_widget user_data) if (docsactif-gtsauve) (docsactif) = tmp else print_warning (Aucun document ouvert)

Il ne faut pas oublier que lutilisateur peut annuler lenregistrement de ce fait nous sauvegardons leacutetat du documentet si la sauvegarde na pas eu lieu on le restaure

VIII-D - Code source

chapitre8zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 27 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IX - Creacuteer un nouveau document

IX-A - Aperccedilu

Cliquez pour agrandir

IX-B - Nouveau fichier

Maintenant que lutilisateur peut ouvrir et fermer un fichier il est inteacuteressant de lui donner la possibiliteacute den creacuteerun nouveau Je ne reviens pas sur la creacuteation du bouton (ccedila devrait deacutejagrave ecirctre fait D) passons directement agrave lafonction cb_new

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) Pour linstant il faut allouer la memoire par la suite on modifiera simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = NULL Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = GTK_TEXT_VIEW (user_data) Le document vient detre creer il nest donc pas modifie docsactif-gtsauve = TRUE gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Je ne sais pas vous mais pour ma part jai fait un copiercoller de la fonction open_file Et oui ouvrir un document peutse reacutesumer agrave creacuteer un document vide puis remplir le GtkTextView avec le fichier souhaiteacute On peut donc simplifiernotre fonction open_file ainsi

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

cb_new (NULL p_text_view) gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE) p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1) Nous sommes obliges de remetre sauve a TRUE car linsertion du contenu du fichier dans le GtkTextView a appele cb_modfie docsactif-gtsauve = TRUE else print_warning (Impossible douvrir le fichier sn file_name)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 28 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc

Cest beau la factorisation du code Par contre nous sommes obligeacutes de remettre sauve agrave TRUE car nous avonsmodifieacute le GtkTextBuffer

IX-C - Code source

chapitre9zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 29 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

X - Fermer

X-A - Aperccedilu

Cliquez pour agrandir

X-B - Fermer un fichier

Maintenant que nous allouons de la meacutemoire il faut la libeacuterer agrave un endroit Logiquement cela va ecirctre fait agrave la fermeturedu document en guise dexercice je vous laisse creacuteer le bouton dans notre boicircte agrave bouton

Allez je vous aide le stock id correspondant est GTK_STOCK_CLOSE

Voilagrave maintenant si tout cest bien passeacute vous devriez ecirctre arriveacute dans le fichier callbackc avec quelque choseressemblant agrave

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data)

Lorsque lon ferme un document il faut vider le GtkTextView (avec les onglets on se contentera de le supprimer)pour cela il faut reacutecupeacuterer le deacutebut et la fin du GtkTextBuffer et demander agrave GTK+ de supprimer tout ce qui ce trouveentre les deux iteacuterateurs

callbackc Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) gtk_text_buffer_delete (p_text_buffer ampstart ampend) else print_warning (Aucun document ouvert)

Bien sucircr il ne faut pas oublier de libeacuterer la meacutemoire

callbackc g_free (docsactif-gtchemin) docsactif-gtchemin = NULL docsactif-gtp_text_view = NULL g_free (docsactif) docsactif = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 30 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour symboliser la fermeture dun document nous deacutesactivons le GtkTextView lors de la fermeture (ne pas oublierde le faire aussi dans mainc)

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) FALSE)

Et nous le reacuteactivons lors de louverture si celle si reacuteussie

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Lorsque lutilisateur quitte lapplication il faut bien sucircr fermer le document sil y en a un ouvert

void cb_quit (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data) gtk_main_quit()

Et aussi lorsquil creacuteeacute un nouveau document (et par conseacutequent lorsquil ouvre un fichier puisque lon fait appel agravecb_new)

void cb_new (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data)

X-C - Enregistrer avant de fermer

Si le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde geacuteneacuteralement le programme le signale agrave lutilisateur etlui propose de sauvegarder ou dannuler la fermeture Pour se faire nous devons modifier la fonction cb_close avantde fermer le document nous allons afficher une boicircte de dialogue

Pour creacuteer une boicircte de dialogue simplement il existe la classe GtkDialog et comme nous avons besoin de boutons(pour que lutilisateur fasse son choix) nous allons creacuteer notre boicircte avec la fonction

GtkWidget gtk_dialog_new_with_buttons (const gchar title GtkWindow parent GtkDialogFlags flags const gchar first_button_text )

Nous retrouvons les mecircmes options que pour le GtkFileChooserDialog mis agrave part option du type GtkDialogFlags

typedef enum GTK_DIALOG_MODAL = 1 ltlt 0 appel gtk_window_set_modal (win TRUE) GTK_DIALOG_DESTROY_WITH_PARENT = 1 ltlt 1 appel gtk_window_set_destroy_with_parent () GTK_DIALOG_NO_SEPARATOR = 1 ltlt 2 Pas de barre de separation au dessus des boutons GtkDialogFlags

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 31 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Nous nous contenterons de rendre notre fenecirctre modale (7)

Pour avoir accegraves agrave notre fenecirctre principale nous ajoutons un champs p_main_window agrave notre structure globaledocs_t que nous initialisons dans la fonction main

mainc docsp_main_window = GTK_WINDOW (p_window)

Il nous reste plus qua creacuteer notre boicircte de dialogue avec trois boutons Oui Non Annuler

callbackc if (docsactif-gtsauve) GtkWidget p_dialog = NULL

p_dialog = gtk_dialog_new_with_buttons (Sauvegarder docsp_main_window GTK_DIALOG_MODAL GTK_STOCK_YES GTK_RESPONSE_YES GTK_STOCK_NO GTK_RESPONSE_NO GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL NULL)

Nous obtenons donc une structure de type GtkDialog

typedef struct GtkWidget vbox GtkWidget action_area GtkDialog

Nous remarquons que cette structure contient deux membres qui permettent dacceacuteder agrave une GtkBox ougrave nous allonsajouter le contenu de la fenecirctre et agrave la partie contenant les boutons

Ensuite la construction de la fenecirctre est identique agrave celle de la fenecirctre principale ici nous nous contenterons dajouterun GtkLabel

callbackc GtkWidget p_label = NULL p_label = gtk_label_new (Voulez-vous sauvegarder les modifications ) gtk_box_pack_start (GTK_BOX (GTK_DIALOG (p_dialog)-gtvbox) p_label TRUE TRUE 0)

Une fois notre fenecirctre precircte il suffit de faire appel agrave la fonction gtk_dialog_run qui va afficher notre GtkDialog et nousretourner le reacuteponse id correspondant au bouton cliqueacute par lutilisateur

callbackc switch (gtk_dialog_run (GTK_DIALOG (p_dialog))) case GTK_RESPONSE_YES cb_save (p_widget user_data) break case GTK_RESPONSE_NO break case GTK_RESPONSE_CANCEL gtk_widget_destroy (p_dialog) return break

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 32 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc gtk_widget_destroy (p_dialog)

Si lutilisateur clique sur non on ne fait rien (le document sera simplement fermeacute) sur oui on enregistre avant defermer et pour finir sil annule on quitte la fonction

X-D - Code source

chapitre10zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 33 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XI - Les barres de deacutefilement

XI-A - Aperccedilu

Cliquez pour agrandir

XI-B - Ajouter des barres de deacutefilement

Apregraves le dernier chapitre quelque peu laborieux voici une partie plus simple mais qui va rendre notre applicationplus pratique En effet si vous avez essayeacute douvrir un fichier de grande taille vous avez pu remarquer que pourpouvoir lire la fin du fichier il fallait utiliser les touches du clavier pas tregraves convivial

Pour rendre la navigation plus aiseacutee on utilise des barres de deacutefilement

mainc GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_scrolled_window TRUE TRUE 0)

Creation de la zone de texte gtk_container_add (GTK_CONTAINER (p_scrolled_window) p_text_view)

Le constructeur de notre GtkScrolledWindow prend en argument deux GtkAdjustment qui permettent de deacutefinirdiffeacuterentes proprieacuteteacutes de la barre de deacutefilement (taille dune page la position de deacutepart) nous laissons GTK+ faireen passant NULL

Cest un bon deacutebut mais estheacutetiquement on peut faire mieux mecircme sil nest pas utile davoir une barre de deacutefilementelle est quand mecircme afficheacutee On peut demander agrave GTK+ de les afficher que si cela est neacutecessaire

mainc gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC)

En fait nous avons de la chance car la classe GtkTextView fait partie des widget qui supporte de faccedilon native les barresde deacutefilement Comment le savoir Ce genre de widget possegravede une ou deux proprieacuteteacutes de type GtkAdjustment (unepour la barre verticale lautre pour la barre horizontale) Actuellement seulement trois classes en sont capables lesGtkTextView les GtkTreeView et les GtkLayout

Comment faire pour les autres widgets Il faut passer par une classe adaptateur GtkViewport afin de creacuteer lesGtkAdjustment

XI-C - Code source

chapitre11zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 34 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XII - Les menus

XII-A - Aperccedilu

Cliquez pour agrandir

XII-B - Creacuteation du menu

Pour simplifier nous avons utiliseacute des boutons pour permettre agrave lutilisateur de creacuteer un document ouvrir un fichierMais il est plus courant dutiliser un menu pour afficher ces options GTK+ propose trois maniegraveres de creacuteer un menu

bull GtkItemFactory cette meacutethode est obsolegravete depuis la version 24 de GTK+

bull GtkUIManager cest ce quon appel une usine agrave gaz pour en savoir plus vous pouvez vous reporter aututoriel Utilisation de GtkUIManager

bull GtkMenu cest ce widget que nous allons eacutetudier il permet de creacuteer un menu manuellement (agrave lopposeacute deGtkUIManager)

Un menu selon GTK+ est composeacute de plusieurs eacuteleacutements

bull GtkMenuBar la barre de menu elle-mecircme

bull GtkMenu la partie deacuteroulante qui contient les diffeacuterents eacuteleacutements

bull GtkMenuItem cest sur ce widget que lutilisateur clique pour lancer une action

Pour commencer faisons linventaire de ce que nous avons besoin

bull Un GtkMenuBar qui sert de base au menu

bull Un GtkMenu pour commencer nous nous aurons dun menu Fichier

bull Six GtkMenuItem pour remplacer nos six boutons

Commenccedilons par la creacuteation du menu nous mettons ce code dans un nouveau fichier dont seul la fonction menu_newsera accessible

menucGtkMenuBar menu_new (gpointer user_data) GtkWidget p_menu_bar = NULL

p_menu_bar = gtk_menu_bar_new () return GTK_MENU_BAR (p_menu_bar)

Le paramegravetre user_data nous servira lors de la connexion des callbacks (nous en avons besoin pour les fonctionscb_new et cb_open)

Ensuite nous allons creacuteer notre sous menu Fichier

menuc Menu Fichier

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 35 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

menuc GtkWidget p_menu = NULL GtkWidget p_menu_item = NULL

p_menu = gtk_menu_new () p_menu_item = gtk_menu_item_new_with_mnemonic (_Fichier) gtk_menu_item_set_submenu (GTK_MENU_ITEM (p_menu_item) p_menu) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu_bar) p_menu_item) return GTK_MENU_BAR (p_menu_bar)

Un sous menu est en fait un GtkMenuItem auquel on assigne un GtkMenu Il faut bien sucircr terminer la creacuteation dusous-menu en lajoutant agrave la barre de menu

Pour finir nous creacuteons les eacuteleacutements du menu les GtkItemMenu Il existe plusieurs types deacuteleacutements (comparableaux diffeacuterents types de bouton) pour commencer nous nutiliserons que le type de base Comme cette opeacuteration estreacutepeacutetitive nous allons creacuteer une fonction pour le faire

menucstatic void menu_item_new (GtkMenu p_menu const gchar title GCallback callback gpointer user_data) GtkWidget p_menu_item = NULL

p_menu_item = gtk_menu_item_new_with_mnemonic (title) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu) p_menu_item) g_signal_connect (G_OBJECT (p_menu_item) activate callback user_data)

Pour permettre agrave lutilisateur dacceacuteder aux diffeacuterents eacuteleacutements du menu agrave laide de la touche ltAltgt nous utilisonsdes mneacutemoniques par exemple pour quitter leacutediteur il suffit de faite Alt+F puis Q Et voici le code pour creacuteer nossix eacuteleacutements du menu

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau G_CALLBACK (cb_new) user_data) menu_item_new (GTK_MENU (p_menu) _Ouvrir G_CALLBACK (cb_open) user_data) menu_item_new (GTK_MENU (p_menu) _Enregistrer G_CALLBACK (cb_save) user_data) menu_item_new (GTK_MENU (p_menu) Enregistrer _sous G_CALLBACK (cb_saveas) user_data) menu_item_new (GTK_MENU (p_menu) _Fermer G_CALLBACK (cb_close) user_data) menu_item_new (GTK_MENU (p_menu) _Quitter G_CALLBACK (cb_quit) user_data)

Voilagrave notre menu est creacuteeacute il nous reste plus quagrave linteacutegrer agrave notre fenecirctre

mainc gtk_box_pack_start (GTK_BOX (p_main_box) GTK_WIDGET (menu_new (p_text_view)) FALSE FALSE 0)

Le problegraveme cest que nous avons besoin de passer le GtkTextView lors de la creacuteation du menu (qui est utiliseacute par lesfonctions cb_new et cb_open) or celui-ci est creacuteeacute apregraves le menu (puisque nous creacuteons les widgets dans lordre ougrave ilfaut les inteacutegrer agrave linterface (8) ) nous devons creacuteer le GtkTextView (seul lappel agrave gtk_text_view_new est deacuteplaceacute)

XII-C - Code source

chapitre12zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 36 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIII - Les barres doutils

XIII-A - Aperccedilu

Cliquez pour agrandir

XIII-B - Creacuteation dune barre doutils

La creacuteation dune barre doutils ressemble fort agrave celle dun menu en plus simple puisquil ny a pas de sous menu on creacutee notre barre doutils (gtk_toolbar_new) puis les eacuteleacutements de la barre pour cela on utilise des boutons(gtk_tool_button_new_from_stock) que lon inseacutere dans la barre (gtk_toolbar_insert) Pas conseacutequent notre fichierbarreoutilsc ressemble agrave menuc

barreoutilscinclude ltgtkgtkhgtinclude callbackhinclude barreoutilsh

static void toolbar_item_new (GtkToolbar const gchar GCallback gpointer)

GtkToolbar toolbar_new (gpointer user_data) GtkWidget p_toolbar = NULL

p_toolbar = gtk_toolbar_new () toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_NEW G_CALLBACK (cb_new) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_OPEN G_CALLBACK (cb_open) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE G_CALLBACK (cb_save) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE_AS G_CALLBACK (cb_saveas) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_CLOSE G_CALLBACK (cb_close) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_QUIT G_CALLBACK (cb_quit) user_data) return GTK_TOOLBAR (p_toolbar)

static void toolbar_item_new (GtkToolbar p_toolbar const gchar stock_id GCallback callback gpointer user_data) GtkToolItem p_tool_item = NULL

p_tool_item = gtk_tool_button_new_from_stock (stock_id) g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data) gtk_toolbar_insert (p_toolbar p_tool_item -1)

Le code nest pas complet car lorsque jexeacutecute le programme GTK+ affiche en plus des icocircnes le texte sous lesboutons Pour modifier cela il suffit dajouter une ligne de code

barreoutilsc gtk_toolbar_set_style (GTK_TOOLBAR (p_toolbar) GTK_TOOLBAR_ICONS)

Pourquoi gtk_tool_button_new_from_stock retourne un GtkToolItem et non un GtkWidgetcomme nous avons eacuteteacute habitueacute jusquagrave preacutesent Il sagit dune bizarrerie de GTK+ dontje ne connais pas la raison

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 37 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour anticiper un changement dinterface (dans GTK+ 30 peut ecirctre ) nous aurions pueacutecrire

Gtkwidget p_tool_item = NULL

p_tool_item = GTK_WIDGET (gtk_tool_button_new_from_stock (stock_id))g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data)gtk_toolbar_insert (p_toolbar GTK_TOOL_ITEM (p_tool_item) -1)

XIII-C - Code source

chapitre13zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 38 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIV - Les racourcis clavier

XIV-A - Aperccedilu

Cliquez pour agrandir

XIV-B - Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mneacutemoniques ces derniers permettent dacceacuteder agrave un eacuteleacutementseacutequentiellement alors que les raccourcis appellent une fonction si lutilisateur appuie simultaneacutement sur une ouplusieurs touches (geacuteneacuteralement de la forme ltModificateurgtTouche ougrave Modificateur repreacutesente les touches ShiftAlt et Control) Ce raccourci peut ecirctre attacheacute agrave un eacuteleacutement du menu mais ceci nest pas obligatoire

Les raccourcis sont regroupeacutes en groupe dans un GtkAccelGroup quil faut commencer par creacuteer

raccourciscinclude ltgtkgtkhgtinclude callbackhinclude raccourcish

GtkAccelGroup accel_group_new (gpointer user_data) GtkAccelGroup p_accel_group = NULL

p_accel_group = gtk_accel_group_new () return p_accel_group

Vous commencez agrave avoir lhabitude de cette organisation nous allons donc creacuteer une fonction qui va se chargerdajouter un raccourci au groupe

raccourciscstatic void accelerator_new (GtkAccelGroup p_accel_group const gchar accelerator const gchar accel_path GCallback callback gpointer user_data) guint key GdkModifierType mods GClosure closure = NULL

gtk_accelerator_parse (accelerator ampkey ampmods) closure = g_cclosure_new (callback user_data NULL) gtk_accel_group_connect (p_accel_group key mods GTK_ACCEL_VISIBLE closure) gtk_accel_map_add_entry (accel_path key mods)

La fonction gtk_accelerator_parse permet de deacutecomposer une chaicircne de caractegraveres de la forme ltControlgtF1 ouencore ltAltgtA en numeacutero de touche et modificateur

En plus des touches pour creacuteer un raccourci clavier nous avons besoin dune fonction agrave appeler lorsque lutilisateurappuie sur les touches speacutecifieacutees gtk_accel_group_connect attend une fonction du type GClosure regardons ladocumentation de gobject pour savoir agrave quoi cela correspond

typedef struct

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 18 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

Pour en finir avec louverture dun fichier il nous reste agrave copier contents dans le GtkTextView En fait le GtkTextViewne gegravere que la forme pour modifier le contenu il faut passer par les GtkTextBuffer Commenccedilons donc par reacutecupeacutererce fameux GtkTextBuffer

callbackc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (p_text_view)

Et pour finir on utilise la fonction

void gtk_text_buffer_insert (GtkTextBuffer buffer GtkTextIter iter const gchar text gint len)

Reacutecapitulons buffer est le GtkTextBuffer que lon vient de reacutecupeacuterer text cest le texte agrave afficher et len la taille dece dernier (ou -1 sil sagit dune chaicircne de caractegraveres au sens du langage C)

Mais quest-ce donc ce GtkTextIter On peut voir cela comme un curseur virtuel qui indique la position agrave laquelleeffectuer linsertion de texte dans le GtkTextBuffer (5) Allons voir ce que la documentation peut nous apprendreagrave leur sujet (6)

typedef struct GtkTextIter is an opaque datatype ignore all these fields Initialize the iter with gtk_text_buffer_get_iter_ functions GtkTextIter

Voilagrave on a notre solution suffit de rechercher les fonctions commenccedilant par gtk_text_buffer_get_iter_ voici la liste

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)

La fonction gtk_text_buffer_get_iter_at_line fait parfaitement laffaire

callbackc GtkTextIter iter

gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1)

Cependant si vous ne voulez pas avoir de problegravemes avec le codage des caractegraveres il vaut mieux convertir le codagelocal vers utf8 Voici le reacutesultat final

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 19 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gchar utf8 = NULL GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_text_buffer_insert (p_text_buffer ampiter utf8 -1) g_free (utf8) utf8 = NULL

V-D - La petite touche finale

Pour finir cette laborieuse partie sur une petite touche estheacutetique nous allons demander agrave GTK+ de nous lancerlapplication en plein eacutecran Pour se faire il suffit dajouter lors de la creacuteation de la fenecirctre principale

maincgtk_window_maximize (GTK_WINDOW (p_window))

On peut mecircme se permettre une pointe dexcentriciteacute en modifiant le titre de notre fenecirctre

maincgtk_window_set_title (GTK_WINDOW (p_window) Editeur de texte en GTK+)

V-E - Code source

chapitre5zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 20 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VI - Choisir un fichier

VI-A - Aperccedilu

Cliquez pour agrandir

VI-B - Utilisation dun GtkFileChooserFile

Jusquagrave preacutesent lutilisateur navait pas le choix quant au fichier agrave ouvrir heureusement GTK+ vient agrave notre aide gracircceau widget GtkFileChooserFile qui est tout simplement une boicircte de dialogue qui propose agrave lutilisateur de seacutelectionnerun fichier dans son arborescence disque

Commenccedilons par creacuteer notre boicircte de dialogue dans la fonction cb_open

callbackcvoid cb_open (GtkWidget p_widget gpointer user_data) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Ouvrir un fichier NULL GTK_FILE_CHOOSER_ACTION_OPEN GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_OPEN GTK_RESPONSE_ACCEPT NULL)

Cette fonction neacutecessite le titre de la boicircte de dialogue une fenecirctre parente le type daction (ici on souhaite ouvrir unfichier GTK+ autorisera lutilisateur agrave seacutelectionner uniquement les fichiers existants) Pour finir il sagit dun couple devaleurs GTK_STOCK_ITEMGTK_STOCK_RESPONSE qui permet de creacuteer un bouton utilisant le stock ID speacutecifieacuteet lorsque celui-ci est cliqueacute la fonction servant agrave lancer la boicircte de dialogue retournera le reacuteponse ID correspondantIl existe une seacuterie de valeurs deacutefinies par GTK+ quil est conseilleacute dutiliser

typedef enum GTK returns this if a response widget has no response_id or if the dialog gets programmatically hidden or destroyed GTK_RESPONSE_NONE = -1

GTK wont return these unless you pass them in as the response for an action widget They are for your convenience GTK_RESPONSE_REJECT = -2 GTK_RESPONSE_ACCEPT = -3

If the dialog is deleted GTK_RESPONSE_DELETE_EVENT = -4

These are returned from GTK dialogs and you can also use them yourself if you like GTK_RESPONSE_OK = -5 GTK_RESPONSE_CANCEL = -6 GTK_RESPONSE_CLOSE = -7 GTK_RESPONSE_YES = -8

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 21 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GTK_RESPONSE_NO = -9 GTK_RESPONSE_APPLY = -10 GTK_RESPONSE_HELP = -11 GtkResponseType

Nous indiquons la fin des couples stock idreacuteponse id avec la valeur NULL

Une fois la boicircte de dialogue creacuteee on demande agrave GTK+ de lafficher gracircce agrave la fonction gtk_dialog_run puis onreacutecupegravere sa valeur de retour qui correspond au bouton cliqueacute par lutilisateur

callbackc if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

Ici ce qui nous inteacuteresse cest lorsque que lutilisateur clique sur le bouton ouvrir (donc gtk_dialog_run renvoieGTK_RESPONSE_ACCEPT) dans ce cas il nous suffit de reacutecupeacuterer le nom du fichier seacutelectionneacute puis de louvrir

callbackc gchar file_name = NULL

file_name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) open_file (file_name GTK_TEXT_VIEW (user_data)) g_free (file_name) file_name = NULL

Pour finir dans tous les cas on noublie pas de deacutetruire la boicircte de dialogue

callbackc gtk_widget_destroy (p_dialog)

Et voilagrave le travail lutilisateur peut ouvrir le fichier quil souhaite

VI-C - Code source

chapitre6zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 22 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VII - Interlude

Avant daller plus loin dans lameacutelioration de linterface de notre eacutediteur il est neacutecessaire de modifier sonfonctionnement interne (ne vous inquieacutetez je nai pas dit chambouler) en effet souvenez-vous dans lintroduction jaieacutevoqueacute la possibiliteacutes douvrir plusieurs documents gracircce agrave un systegraveme donglets Pour cela il faut sauvegarder lesproprieacuteteacutes de chaque document ouvert Pris agrave temps ce genre de modification nest pas trop lourde mais si nousattendons cela risque de devenir un vrai casse tecircte

Pour cela nous allons utiliser une structure de donneacutee pour chaque document ouvert qui devra garder en meacutemoirele chemin complet du fichier (ou NULL si le document nest pas encore sauvegarder) sil agrave eacutetait modifier depuis laderniegravere sauvegarde et le GtkTextView qui sert agrave son affichage Voici donc la structure qui va nous servir

documenthtypedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

Sachant que nous serons ameneacute agrave stocker plusieurs occurrences de cette structure il serait bon de reacutefleacutechir degravesmaintenant agrave la structure de donneacutee agrave utiliser pour les stocker La premiegravere ideacutee qui vient agrave lesprit est un tableaualloueacute dynamiquement cependant lutilisateur peut souhaiter fermer un document qui se trouve au milieu on estalors obligeacute de deacutecaler toutes les cellules en amont Dans ce cas il parait naturel dutiliser une liste chaicircneacutee Parchance la glib propose une bibliothegraveque de gestion des listes chaicircneacutees cela nous fera gagner du temps le momentvenu Pour linstant on se contente de creacuteer une structure de donneacutees qui contiendra tous les documents ouverts(stockeacutee dans une GList) et un pointeur sur le document actif (actuellement comme nous navons quun documentouvert en mecircme temps on manipulera uniquement ce pointeur)

documenthtypedef struct GList tous document_t actif docs_t

Maintenant se pose le problegraveme de savoir comment transmettre cette structure On pourrait se servir du paramegravetreuser_data preacutesent dans toutes les fonctions callback mais certaines fonctions utilise deacutejagrave ce paramegravetre (la fonctioncb_open par exemple) il faudrait creacuteer un champs suppleacutementaire dans notre structure documents_s Une solutionplus simple est de creacuteer une variable globale agrave lensemble du programme Ceux qui passe reacuteguliegraverement sur le forumC savent que cest fortement deacuteconseilleacute mais ici nous nous trouvons dans lune des rares exceptions agrave la regravegle Detoute faccedilon cela revient au mecircme que de passer ladresse de notre structure agrave toutes les fonctions callback Nousdeacutefinissons donc un nouveau fichier den-tecircte

documenthifndef H_DOCUMENTdefine H_DOCUMENT

include ltgtkgtkhgt

typedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 23 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

documenthtypedef struct GList tous document_t actif docs_t

extern docs_t docs

endif not H_DOCUMENT

Et dans le fichier mainc

maincinclude documenth

docs_t docs = NULL NULL

Pour linstant la seule fonction qui modifie leacutetat dun document est la fonction open_file il faut donc inclure documenthdans callbackc et modifier leacutegegraverement la fonction pour enregistrer le document ouvert

callbackc if (g_file_get_contents (file_name ampcontents NULL NULL)) Pour linstant il faut allouer la memoire par la suite on modifira simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = g_strdup (file_name) Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = p_text_view Le document vient detre ouvert il nest donc pas modifie docsactif-gtsauve = TRUE

Ne soyez pas choqueacute si je ne teste pas le retour de la fonction g_malloc pour veacuterifier quilnest pas NULL En effet cette derniegravere met fin agrave lapplication si lallocation eacutechoue

VII-A - Code source

chapitre7zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 24 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VIII - Sauvegarder les modification

VIII-A - Aperccedilu

Cliquez pour agrandir

VIII-B - Enregistrer

Avant de pouvoir sauvegarder un document il faut quil soit modifieacute Comment savoir que le contenu du fichier a eacuteteacutemodifier Gracircce au signal changed du GtkTextBuffer que nous interceptons gracircce agrave la fonction cb_modifie

mainc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (p_text_view)) g_signal_connect (G_OBJECT (p_text_buffer) changed G_CALLBACK (cb_modifie) NULL)

Cette derniegravere modifie simplement le champ sauve du document

callbackcvoid cb_modifie (GtkWidget p_widget gpointer user_data) if (docsactif) docsactif-gtsauve = FALSE

Pour la sauvegarde il faut distinguer deux cas soit il sagit de la premiegravere sauvegarde du fichier il faut alors demanderle nom du fichier agrave lutilisateur (cela ressemble fortement agrave louverture dun fichier) soit le fichier est deacutejagrave preacutesent surle disque il suffit de remplacer son contenu par celui du GtkTextViewer Nous avons convenu quun fichier qui neacutetaitpas encore enregistreacute avait sa proprieacuteteacute chemin agrave NULL

Bien sucircr cela na lieu que si un fichier est ouvert et quil a eacuteteacute modifieacute depuis sa derniegravere sauvegarde

callbackcvoid cb_save (GtkWidget p_widget gpointer user_data) if (docsactif) if (docsactif-gtsauve) Le fichier na pas encore ete enregistre if (docsactif-gtchemin) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Sauvegarder le fichier NULL GTK_FILE_CHOOSER_ACTION_SAVE GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_SAVE GTK_RESPONSE_ACCEPT NULL) if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 25 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc docsactif-gtchemin = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) gtk_widget_destroy (p_dialog) Soit le fichier a deja ete enregistre soit lutilisateur vient de nous fournir son nouvel enplacement on peut donc lenregistrer if (docsactif-gtchemin) else print_warning (Aucun document ouvert)

Il nous reste plus quagrave reacutecupeacuterer le contenu du GtkTextViewer et le copier dans le fichier chemin sans oublier dereconvertir le texte dans le codage local

callbackc FILE fichier = NULL

fichier = fopen (docsactif-gtchemin w) if (fichier) gchar contents = NULL gchar locale = NULL GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) contents = gtk_text_buffer_get_text (p_text_buffer ampstart ampend FALSE) locale = g_locale_from_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL fprintf (fichier s locale) g_free (locale) locale = NULL fclose (fichier) fichier = NULL docsactif-gtsauve = TRUE else print_warning (Impossible de sauvegarder le fichier s docsactif-gtchemin)

Le dernier paramegravetre de la fonction gtk_text_buffer_get_text est mis agrave FALSE car nous ne voulons pas enregistrerles caractegraveres invisibles preacutesent dans le GtkTextBuffer Ces caractegraveres servent agrave mettre en forme le texte (taillecouleur) nous pourrions creacuteer un nouveau format de fichier pour enregistrer la mise en forme

VIII-C - Enregistrer sous

Pour enregistrer notre document sous un autre nom il suffit de faire croire agrave cb_save que le document na pas encoreeacutetait enregistreacute tout simplement en changeant chemin agrave NULL et sauve agrave FALSE

callbackcvoid cb_saveas (GtkWidget p_widget gpointer user_data)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 26 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (docsactif) document_t tmp = docsactif

docsactif-gtchemin = NULL docsactif-gtsauve = FALSE cb_save (p_widget user_data) if (docsactif-gtsauve) (docsactif) = tmp else print_warning (Aucun document ouvert)

Il ne faut pas oublier que lutilisateur peut annuler lenregistrement de ce fait nous sauvegardons leacutetat du documentet si la sauvegarde na pas eu lieu on le restaure

VIII-D - Code source

chapitre8zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 27 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IX - Creacuteer un nouveau document

IX-A - Aperccedilu

Cliquez pour agrandir

IX-B - Nouveau fichier

Maintenant que lutilisateur peut ouvrir et fermer un fichier il est inteacuteressant de lui donner la possibiliteacute den creacuteerun nouveau Je ne reviens pas sur la creacuteation du bouton (ccedila devrait deacutejagrave ecirctre fait D) passons directement agrave lafonction cb_new

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) Pour linstant il faut allouer la memoire par la suite on modifiera simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = NULL Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = GTK_TEXT_VIEW (user_data) Le document vient detre creer il nest donc pas modifie docsactif-gtsauve = TRUE gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Je ne sais pas vous mais pour ma part jai fait un copiercoller de la fonction open_file Et oui ouvrir un document peutse reacutesumer agrave creacuteer un document vide puis remplir le GtkTextView avec le fichier souhaiteacute On peut donc simplifiernotre fonction open_file ainsi

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

cb_new (NULL p_text_view) gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE) p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1) Nous sommes obliges de remetre sauve a TRUE car linsertion du contenu du fichier dans le GtkTextView a appele cb_modfie docsactif-gtsauve = TRUE else print_warning (Impossible douvrir le fichier sn file_name)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 28 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc

Cest beau la factorisation du code Par contre nous sommes obligeacutes de remettre sauve agrave TRUE car nous avonsmodifieacute le GtkTextBuffer

IX-C - Code source

chapitre9zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 29 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

X - Fermer

X-A - Aperccedilu

Cliquez pour agrandir

X-B - Fermer un fichier

Maintenant que nous allouons de la meacutemoire il faut la libeacuterer agrave un endroit Logiquement cela va ecirctre fait agrave la fermeturedu document en guise dexercice je vous laisse creacuteer le bouton dans notre boicircte agrave bouton

Allez je vous aide le stock id correspondant est GTK_STOCK_CLOSE

Voilagrave maintenant si tout cest bien passeacute vous devriez ecirctre arriveacute dans le fichier callbackc avec quelque choseressemblant agrave

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data)

Lorsque lon ferme un document il faut vider le GtkTextView (avec les onglets on se contentera de le supprimer)pour cela il faut reacutecupeacuterer le deacutebut et la fin du GtkTextBuffer et demander agrave GTK+ de supprimer tout ce qui ce trouveentre les deux iteacuterateurs

callbackc Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) gtk_text_buffer_delete (p_text_buffer ampstart ampend) else print_warning (Aucun document ouvert)

Bien sucircr il ne faut pas oublier de libeacuterer la meacutemoire

callbackc g_free (docsactif-gtchemin) docsactif-gtchemin = NULL docsactif-gtp_text_view = NULL g_free (docsactif) docsactif = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 30 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour symboliser la fermeture dun document nous deacutesactivons le GtkTextView lors de la fermeture (ne pas oublierde le faire aussi dans mainc)

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) FALSE)

Et nous le reacuteactivons lors de louverture si celle si reacuteussie

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Lorsque lutilisateur quitte lapplication il faut bien sucircr fermer le document sil y en a un ouvert

void cb_quit (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data) gtk_main_quit()

Et aussi lorsquil creacuteeacute un nouveau document (et par conseacutequent lorsquil ouvre un fichier puisque lon fait appel agravecb_new)

void cb_new (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data)

X-C - Enregistrer avant de fermer

Si le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde geacuteneacuteralement le programme le signale agrave lutilisateur etlui propose de sauvegarder ou dannuler la fermeture Pour se faire nous devons modifier la fonction cb_close avantde fermer le document nous allons afficher une boicircte de dialogue

Pour creacuteer une boicircte de dialogue simplement il existe la classe GtkDialog et comme nous avons besoin de boutons(pour que lutilisateur fasse son choix) nous allons creacuteer notre boicircte avec la fonction

GtkWidget gtk_dialog_new_with_buttons (const gchar title GtkWindow parent GtkDialogFlags flags const gchar first_button_text )

Nous retrouvons les mecircmes options que pour le GtkFileChooserDialog mis agrave part option du type GtkDialogFlags

typedef enum GTK_DIALOG_MODAL = 1 ltlt 0 appel gtk_window_set_modal (win TRUE) GTK_DIALOG_DESTROY_WITH_PARENT = 1 ltlt 1 appel gtk_window_set_destroy_with_parent () GTK_DIALOG_NO_SEPARATOR = 1 ltlt 2 Pas de barre de separation au dessus des boutons GtkDialogFlags

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 31 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Nous nous contenterons de rendre notre fenecirctre modale (7)

Pour avoir accegraves agrave notre fenecirctre principale nous ajoutons un champs p_main_window agrave notre structure globaledocs_t que nous initialisons dans la fonction main

mainc docsp_main_window = GTK_WINDOW (p_window)

Il nous reste plus qua creacuteer notre boicircte de dialogue avec trois boutons Oui Non Annuler

callbackc if (docsactif-gtsauve) GtkWidget p_dialog = NULL

p_dialog = gtk_dialog_new_with_buttons (Sauvegarder docsp_main_window GTK_DIALOG_MODAL GTK_STOCK_YES GTK_RESPONSE_YES GTK_STOCK_NO GTK_RESPONSE_NO GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL NULL)

Nous obtenons donc une structure de type GtkDialog

typedef struct GtkWidget vbox GtkWidget action_area GtkDialog

Nous remarquons que cette structure contient deux membres qui permettent dacceacuteder agrave une GtkBox ougrave nous allonsajouter le contenu de la fenecirctre et agrave la partie contenant les boutons

Ensuite la construction de la fenecirctre est identique agrave celle de la fenecirctre principale ici nous nous contenterons dajouterun GtkLabel

callbackc GtkWidget p_label = NULL p_label = gtk_label_new (Voulez-vous sauvegarder les modifications ) gtk_box_pack_start (GTK_BOX (GTK_DIALOG (p_dialog)-gtvbox) p_label TRUE TRUE 0)

Une fois notre fenecirctre precircte il suffit de faire appel agrave la fonction gtk_dialog_run qui va afficher notre GtkDialog et nousretourner le reacuteponse id correspondant au bouton cliqueacute par lutilisateur

callbackc switch (gtk_dialog_run (GTK_DIALOG (p_dialog))) case GTK_RESPONSE_YES cb_save (p_widget user_data) break case GTK_RESPONSE_NO break case GTK_RESPONSE_CANCEL gtk_widget_destroy (p_dialog) return break

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 32 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc gtk_widget_destroy (p_dialog)

Si lutilisateur clique sur non on ne fait rien (le document sera simplement fermeacute) sur oui on enregistre avant defermer et pour finir sil annule on quitte la fonction

X-D - Code source

chapitre10zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 33 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XI - Les barres de deacutefilement

XI-A - Aperccedilu

Cliquez pour agrandir

XI-B - Ajouter des barres de deacutefilement

Apregraves le dernier chapitre quelque peu laborieux voici une partie plus simple mais qui va rendre notre applicationplus pratique En effet si vous avez essayeacute douvrir un fichier de grande taille vous avez pu remarquer que pourpouvoir lire la fin du fichier il fallait utiliser les touches du clavier pas tregraves convivial

Pour rendre la navigation plus aiseacutee on utilise des barres de deacutefilement

mainc GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_scrolled_window TRUE TRUE 0)

Creation de la zone de texte gtk_container_add (GTK_CONTAINER (p_scrolled_window) p_text_view)

Le constructeur de notre GtkScrolledWindow prend en argument deux GtkAdjustment qui permettent de deacutefinirdiffeacuterentes proprieacuteteacutes de la barre de deacutefilement (taille dune page la position de deacutepart) nous laissons GTK+ faireen passant NULL

Cest un bon deacutebut mais estheacutetiquement on peut faire mieux mecircme sil nest pas utile davoir une barre de deacutefilementelle est quand mecircme afficheacutee On peut demander agrave GTK+ de les afficher que si cela est neacutecessaire

mainc gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC)

En fait nous avons de la chance car la classe GtkTextView fait partie des widget qui supporte de faccedilon native les barresde deacutefilement Comment le savoir Ce genre de widget possegravede une ou deux proprieacuteteacutes de type GtkAdjustment (unepour la barre verticale lautre pour la barre horizontale) Actuellement seulement trois classes en sont capables lesGtkTextView les GtkTreeView et les GtkLayout

Comment faire pour les autres widgets Il faut passer par une classe adaptateur GtkViewport afin de creacuteer lesGtkAdjustment

XI-C - Code source

chapitre11zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 34 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XII - Les menus

XII-A - Aperccedilu

Cliquez pour agrandir

XII-B - Creacuteation du menu

Pour simplifier nous avons utiliseacute des boutons pour permettre agrave lutilisateur de creacuteer un document ouvrir un fichierMais il est plus courant dutiliser un menu pour afficher ces options GTK+ propose trois maniegraveres de creacuteer un menu

bull GtkItemFactory cette meacutethode est obsolegravete depuis la version 24 de GTK+

bull GtkUIManager cest ce quon appel une usine agrave gaz pour en savoir plus vous pouvez vous reporter aututoriel Utilisation de GtkUIManager

bull GtkMenu cest ce widget que nous allons eacutetudier il permet de creacuteer un menu manuellement (agrave lopposeacute deGtkUIManager)

Un menu selon GTK+ est composeacute de plusieurs eacuteleacutements

bull GtkMenuBar la barre de menu elle-mecircme

bull GtkMenu la partie deacuteroulante qui contient les diffeacuterents eacuteleacutements

bull GtkMenuItem cest sur ce widget que lutilisateur clique pour lancer une action

Pour commencer faisons linventaire de ce que nous avons besoin

bull Un GtkMenuBar qui sert de base au menu

bull Un GtkMenu pour commencer nous nous aurons dun menu Fichier

bull Six GtkMenuItem pour remplacer nos six boutons

Commenccedilons par la creacuteation du menu nous mettons ce code dans un nouveau fichier dont seul la fonction menu_newsera accessible

menucGtkMenuBar menu_new (gpointer user_data) GtkWidget p_menu_bar = NULL

p_menu_bar = gtk_menu_bar_new () return GTK_MENU_BAR (p_menu_bar)

Le paramegravetre user_data nous servira lors de la connexion des callbacks (nous en avons besoin pour les fonctionscb_new et cb_open)

Ensuite nous allons creacuteer notre sous menu Fichier

menuc Menu Fichier

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 35 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

menuc GtkWidget p_menu = NULL GtkWidget p_menu_item = NULL

p_menu = gtk_menu_new () p_menu_item = gtk_menu_item_new_with_mnemonic (_Fichier) gtk_menu_item_set_submenu (GTK_MENU_ITEM (p_menu_item) p_menu) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu_bar) p_menu_item) return GTK_MENU_BAR (p_menu_bar)

Un sous menu est en fait un GtkMenuItem auquel on assigne un GtkMenu Il faut bien sucircr terminer la creacuteation dusous-menu en lajoutant agrave la barre de menu

Pour finir nous creacuteons les eacuteleacutements du menu les GtkItemMenu Il existe plusieurs types deacuteleacutements (comparableaux diffeacuterents types de bouton) pour commencer nous nutiliserons que le type de base Comme cette opeacuteration estreacutepeacutetitive nous allons creacuteer une fonction pour le faire

menucstatic void menu_item_new (GtkMenu p_menu const gchar title GCallback callback gpointer user_data) GtkWidget p_menu_item = NULL

p_menu_item = gtk_menu_item_new_with_mnemonic (title) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu) p_menu_item) g_signal_connect (G_OBJECT (p_menu_item) activate callback user_data)

Pour permettre agrave lutilisateur dacceacuteder aux diffeacuterents eacuteleacutements du menu agrave laide de la touche ltAltgt nous utilisonsdes mneacutemoniques par exemple pour quitter leacutediteur il suffit de faite Alt+F puis Q Et voici le code pour creacuteer nossix eacuteleacutements du menu

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau G_CALLBACK (cb_new) user_data) menu_item_new (GTK_MENU (p_menu) _Ouvrir G_CALLBACK (cb_open) user_data) menu_item_new (GTK_MENU (p_menu) _Enregistrer G_CALLBACK (cb_save) user_data) menu_item_new (GTK_MENU (p_menu) Enregistrer _sous G_CALLBACK (cb_saveas) user_data) menu_item_new (GTK_MENU (p_menu) _Fermer G_CALLBACK (cb_close) user_data) menu_item_new (GTK_MENU (p_menu) _Quitter G_CALLBACK (cb_quit) user_data)

Voilagrave notre menu est creacuteeacute il nous reste plus quagrave linteacutegrer agrave notre fenecirctre

mainc gtk_box_pack_start (GTK_BOX (p_main_box) GTK_WIDGET (menu_new (p_text_view)) FALSE FALSE 0)

Le problegraveme cest que nous avons besoin de passer le GtkTextView lors de la creacuteation du menu (qui est utiliseacute par lesfonctions cb_new et cb_open) or celui-ci est creacuteeacute apregraves le menu (puisque nous creacuteons les widgets dans lordre ougrave ilfaut les inteacutegrer agrave linterface (8) ) nous devons creacuteer le GtkTextView (seul lappel agrave gtk_text_view_new est deacuteplaceacute)

XII-C - Code source

chapitre12zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 36 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIII - Les barres doutils

XIII-A - Aperccedilu

Cliquez pour agrandir

XIII-B - Creacuteation dune barre doutils

La creacuteation dune barre doutils ressemble fort agrave celle dun menu en plus simple puisquil ny a pas de sous menu on creacutee notre barre doutils (gtk_toolbar_new) puis les eacuteleacutements de la barre pour cela on utilise des boutons(gtk_tool_button_new_from_stock) que lon inseacutere dans la barre (gtk_toolbar_insert) Pas conseacutequent notre fichierbarreoutilsc ressemble agrave menuc

barreoutilscinclude ltgtkgtkhgtinclude callbackhinclude barreoutilsh

static void toolbar_item_new (GtkToolbar const gchar GCallback gpointer)

GtkToolbar toolbar_new (gpointer user_data) GtkWidget p_toolbar = NULL

p_toolbar = gtk_toolbar_new () toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_NEW G_CALLBACK (cb_new) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_OPEN G_CALLBACK (cb_open) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE G_CALLBACK (cb_save) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE_AS G_CALLBACK (cb_saveas) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_CLOSE G_CALLBACK (cb_close) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_QUIT G_CALLBACK (cb_quit) user_data) return GTK_TOOLBAR (p_toolbar)

static void toolbar_item_new (GtkToolbar p_toolbar const gchar stock_id GCallback callback gpointer user_data) GtkToolItem p_tool_item = NULL

p_tool_item = gtk_tool_button_new_from_stock (stock_id) g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data) gtk_toolbar_insert (p_toolbar p_tool_item -1)

Le code nest pas complet car lorsque jexeacutecute le programme GTK+ affiche en plus des icocircnes le texte sous lesboutons Pour modifier cela il suffit dajouter une ligne de code

barreoutilsc gtk_toolbar_set_style (GTK_TOOLBAR (p_toolbar) GTK_TOOLBAR_ICONS)

Pourquoi gtk_tool_button_new_from_stock retourne un GtkToolItem et non un GtkWidgetcomme nous avons eacuteteacute habitueacute jusquagrave preacutesent Il sagit dune bizarrerie de GTK+ dontje ne connais pas la raison

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 37 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour anticiper un changement dinterface (dans GTK+ 30 peut ecirctre ) nous aurions pueacutecrire

Gtkwidget p_tool_item = NULL

p_tool_item = GTK_WIDGET (gtk_tool_button_new_from_stock (stock_id))g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data)gtk_toolbar_insert (p_toolbar GTK_TOOL_ITEM (p_tool_item) -1)

XIII-C - Code source

chapitre13zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 38 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIV - Les racourcis clavier

XIV-A - Aperccedilu

Cliquez pour agrandir

XIV-B - Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mneacutemoniques ces derniers permettent dacceacuteder agrave un eacuteleacutementseacutequentiellement alors que les raccourcis appellent une fonction si lutilisateur appuie simultaneacutement sur une ouplusieurs touches (geacuteneacuteralement de la forme ltModificateurgtTouche ougrave Modificateur repreacutesente les touches ShiftAlt et Control) Ce raccourci peut ecirctre attacheacute agrave un eacuteleacutement du menu mais ceci nest pas obligatoire

Les raccourcis sont regroupeacutes en groupe dans un GtkAccelGroup quil faut commencer par creacuteer

raccourciscinclude ltgtkgtkhgtinclude callbackhinclude raccourcish

GtkAccelGroup accel_group_new (gpointer user_data) GtkAccelGroup p_accel_group = NULL

p_accel_group = gtk_accel_group_new () return p_accel_group

Vous commencez agrave avoir lhabitude de cette organisation nous allons donc creacuteer une fonction qui va se chargerdajouter un raccourci au groupe

raccourciscstatic void accelerator_new (GtkAccelGroup p_accel_group const gchar accelerator const gchar accel_path GCallback callback gpointer user_data) guint key GdkModifierType mods GClosure closure = NULL

gtk_accelerator_parse (accelerator ampkey ampmods) closure = g_cclosure_new (callback user_data NULL) gtk_accel_group_connect (p_accel_group key mods GTK_ACCEL_VISIBLE closure) gtk_accel_map_add_entry (accel_path key mods)

La fonction gtk_accelerator_parse permet de deacutecomposer une chaicircne de caractegraveres de la forme ltControlgtF1 ouencore ltAltgtA en numeacutero de touche et modificateur

En plus des touches pour creacuteer un raccourci clavier nous avons besoin dune fonction agrave appeler lorsque lutilisateurappuie sur les touches speacutecifieacutees gtk_accel_group_connect attend une fonction du type GClosure regardons ladocumentation de gobject pour savoir agrave quoi cela correspond

typedef struct

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 19 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gchar utf8 = NULL GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_text_buffer_insert (p_text_buffer ampiter utf8 -1) g_free (utf8) utf8 = NULL

V-D - La petite touche finale

Pour finir cette laborieuse partie sur une petite touche estheacutetique nous allons demander agrave GTK+ de nous lancerlapplication en plein eacutecran Pour se faire il suffit dajouter lors de la creacuteation de la fenecirctre principale

maincgtk_window_maximize (GTK_WINDOW (p_window))

On peut mecircme se permettre une pointe dexcentriciteacute en modifiant le titre de notre fenecirctre

maincgtk_window_set_title (GTK_WINDOW (p_window) Editeur de texte en GTK+)

V-E - Code source

chapitre5zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 20 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VI - Choisir un fichier

VI-A - Aperccedilu

Cliquez pour agrandir

VI-B - Utilisation dun GtkFileChooserFile

Jusquagrave preacutesent lutilisateur navait pas le choix quant au fichier agrave ouvrir heureusement GTK+ vient agrave notre aide gracircceau widget GtkFileChooserFile qui est tout simplement une boicircte de dialogue qui propose agrave lutilisateur de seacutelectionnerun fichier dans son arborescence disque

Commenccedilons par creacuteer notre boicircte de dialogue dans la fonction cb_open

callbackcvoid cb_open (GtkWidget p_widget gpointer user_data) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Ouvrir un fichier NULL GTK_FILE_CHOOSER_ACTION_OPEN GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_OPEN GTK_RESPONSE_ACCEPT NULL)

Cette fonction neacutecessite le titre de la boicircte de dialogue une fenecirctre parente le type daction (ici on souhaite ouvrir unfichier GTK+ autorisera lutilisateur agrave seacutelectionner uniquement les fichiers existants) Pour finir il sagit dun couple devaleurs GTK_STOCK_ITEMGTK_STOCK_RESPONSE qui permet de creacuteer un bouton utilisant le stock ID speacutecifieacuteet lorsque celui-ci est cliqueacute la fonction servant agrave lancer la boicircte de dialogue retournera le reacuteponse ID correspondantIl existe une seacuterie de valeurs deacutefinies par GTK+ quil est conseilleacute dutiliser

typedef enum GTK returns this if a response widget has no response_id or if the dialog gets programmatically hidden or destroyed GTK_RESPONSE_NONE = -1

GTK wont return these unless you pass them in as the response for an action widget They are for your convenience GTK_RESPONSE_REJECT = -2 GTK_RESPONSE_ACCEPT = -3

If the dialog is deleted GTK_RESPONSE_DELETE_EVENT = -4

These are returned from GTK dialogs and you can also use them yourself if you like GTK_RESPONSE_OK = -5 GTK_RESPONSE_CANCEL = -6 GTK_RESPONSE_CLOSE = -7 GTK_RESPONSE_YES = -8

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 21 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GTK_RESPONSE_NO = -9 GTK_RESPONSE_APPLY = -10 GTK_RESPONSE_HELP = -11 GtkResponseType

Nous indiquons la fin des couples stock idreacuteponse id avec la valeur NULL

Une fois la boicircte de dialogue creacuteee on demande agrave GTK+ de lafficher gracircce agrave la fonction gtk_dialog_run puis onreacutecupegravere sa valeur de retour qui correspond au bouton cliqueacute par lutilisateur

callbackc if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

Ici ce qui nous inteacuteresse cest lorsque que lutilisateur clique sur le bouton ouvrir (donc gtk_dialog_run renvoieGTK_RESPONSE_ACCEPT) dans ce cas il nous suffit de reacutecupeacuterer le nom du fichier seacutelectionneacute puis de louvrir

callbackc gchar file_name = NULL

file_name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) open_file (file_name GTK_TEXT_VIEW (user_data)) g_free (file_name) file_name = NULL

Pour finir dans tous les cas on noublie pas de deacutetruire la boicircte de dialogue

callbackc gtk_widget_destroy (p_dialog)

Et voilagrave le travail lutilisateur peut ouvrir le fichier quil souhaite

VI-C - Code source

chapitre6zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 22 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VII - Interlude

Avant daller plus loin dans lameacutelioration de linterface de notre eacutediteur il est neacutecessaire de modifier sonfonctionnement interne (ne vous inquieacutetez je nai pas dit chambouler) en effet souvenez-vous dans lintroduction jaieacutevoqueacute la possibiliteacutes douvrir plusieurs documents gracircce agrave un systegraveme donglets Pour cela il faut sauvegarder lesproprieacuteteacutes de chaque document ouvert Pris agrave temps ce genre de modification nest pas trop lourde mais si nousattendons cela risque de devenir un vrai casse tecircte

Pour cela nous allons utiliser une structure de donneacutee pour chaque document ouvert qui devra garder en meacutemoirele chemin complet du fichier (ou NULL si le document nest pas encore sauvegarder) sil agrave eacutetait modifier depuis laderniegravere sauvegarde et le GtkTextView qui sert agrave son affichage Voici donc la structure qui va nous servir

documenthtypedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

Sachant que nous serons ameneacute agrave stocker plusieurs occurrences de cette structure il serait bon de reacutefleacutechir degravesmaintenant agrave la structure de donneacutee agrave utiliser pour les stocker La premiegravere ideacutee qui vient agrave lesprit est un tableaualloueacute dynamiquement cependant lutilisateur peut souhaiter fermer un document qui se trouve au milieu on estalors obligeacute de deacutecaler toutes les cellules en amont Dans ce cas il parait naturel dutiliser une liste chaicircneacutee Parchance la glib propose une bibliothegraveque de gestion des listes chaicircneacutees cela nous fera gagner du temps le momentvenu Pour linstant on se contente de creacuteer une structure de donneacutees qui contiendra tous les documents ouverts(stockeacutee dans une GList) et un pointeur sur le document actif (actuellement comme nous navons quun documentouvert en mecircme temps on manipulera uniquement ce pointeur)

documenthtypedef struct GList tous document_t actif docs_t

Maintenant se pose le problegraveme de savoir comment transmettre cette structure On pourrait se servir du paramegravetreuser_data preacutesent dans toutes les fonctions callback mais certaines fonctions utilise deacutejagrave ce paramegravetre (la fonctioncb_open par exemple) il faudrait creacuteer un champs suppleacutementaire dans notre structure documents_s Une solutionplus simple est de creacuteer une variable globale agrave lensemble du programme Ceux qui passe reacuteguliegraverement sur le forumC savent que cest fortement deacuteconseilleacute mais ici nous nous trouvons dans lune des rares exceptions agrave la regravegle Detoute faccedilon cela revient au mecircme que de passer ladresse de notre structure agrave toutes les fonctions callback Nousdeacutefinissons donc un nouveau fichier den-tecircte

documenthifndef H_DOCUMENTdefine H_DOCUMENT

include ltgtkgtkhgt

typedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 23 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

documenthtypedef struct GList tous document_t actif docs_t

extern docs_t docs

endif not H_DOCUMENT

Et dans le fichier mainc

maincinclude documenth

docs_t docs = NULL NULL

Pour linstant la seule fonction qui modifie leacutetat dun document est la fonction open_file il faut donc inclure documenthdans callbackc et modifier leacutegegraverement la fonction pour enregistrer le document ouvert

callbackc if (g_file_get_contents (file_name ampcontents NULL NULL)) Pour linstant il faut allouer la memoire par la suite on modifira simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = g_strdup (file_name) Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = p_text_view Le document vient detre ouvert il nest donc pas modifie docsactif-gtsauve = TRUE

Ne soyez pas choqueacute si je ne teste pas le retour de la fonction g_malloc pour veacuterifier quilnest pas NULL En effet cette derniegravere met fin agrave lapplication si lallocation eacutechoue

VII-A - Code source

chapitre7zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 24 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VIII - Sauvegarder les modification

VIII-A - Aperccedilu

Cliquez pour agrandir

VIII-B - Enregistrer

Avant de pouvoir sauvegarder un document il faut quil soit modifieacute Comment savoir que le contenu du fichier a eacuteteacutemodifier Gracircce au signal changed du GtkTextBuffer que nous interceptons gracircce agrave la fonction cb_modifie

mainc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (p_text_view)) g_signal_connect (G_OBJECT (p_text_buffer) changed G_CALLBACK (cb_modifie) NULL)

Cette derniegravere modifie simplement le champ sauve du document

callbackcvoid cb_modifie (GtkWidget p_widget gpointer user_data) if (docsactif) docsactif-gtsauve = FALSE

Pour la sauvegarde il faut distinguer deux cas soit il sagit de la premiegravere sauvegarde du fichier il faut alors demanderle nom du fichier agrave lutilisateur (cela ressemble fortement agrave louverture dun fichier) soit le fichier est deacutejagrave preacutesent surle disque il suffit de remplacer son contenu par celui du GtkTextViewer Nous avons convenu quun fichier qui neacutetaitpas encore enregistreacute avait sa proprieacuteteacute chemin agrave NULL

Bien sucircr cela na lieu que si un fichier est ouvert et quil a eacuteteacute modifieacute depuis sa derniegravere sauvegarde

callbackcvoid cb_save (GtkWidget p_widget gpointer user_data) if (docsactif) if (docsactif-gtsauve) Le fichier na pas encore ete enregistre if (docsactif-gtchemin) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Sauvegarder le fichier NULL GTK_FILE_CHOOSER_ACTION_SAVE GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_SAVE GTK_RESPONSE_ACCEPT NULL) if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 25 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc docsactif-gtchemin = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) gtk_widget_destroy (p_dialog) Soit le fichier a deja ete enregistre soit lutilisateur vient de nous fournir son nouvel enplacement on peut donc lenregistrer if (docsactif-gtchemin) else print_warning (Aucun document ouvert)

Il nous reste plus quagrave reacutecupeacuterer le contenu du GtkTextViewer et le copier dans le fichier chemin sans oublier dereconvertir le texte dans le codage local

callbackc FILE fichier = NULL

fichier = fopen (docsactif-gtchemin w) if (fichier) gchar contents = NULL gchar locale = NULL GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) contents = gtk_text_buffer_get_text (p_text_buffer ampstart ampend FALSE) locale = g_locale_from_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL fprintf (fichier s locale) g_free (locale) locale = NULL fclose (fichier) fichier = NULL docsactif-gtsauve = TRUE else print_warning (Impossible de sauvegarder le fichier s docsactif-gtchemin)

Le dernier paramegravetre de la fonction gtk_text_buffer_get_text est mis agrave FALSE car nous ne voulons pas enregistrerles caractegraveres invisibles preacutesent dans le GtkTextBuffer Ces caractegraveres servent agrave mettre en forme le texte (taillecouleur) nous pourrions creacuteer un nouveau format de fichier pour enregistrer la mise en forme

VIII-C - Enregistrer sous

Pour enregistrer notre document sous un autre nom il suffit de faire croire agrave cb_save que le document na pas encoreeacutetait enregistreacute tout simplement en changeant chemin agrave NULL et sauve agrave FALSE

callbackcvoid cb_saveas (GtkWidget p_widget gpointer user_data)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 26 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (docsactif) document_t tmp = docsactif

docsactif-gtchemin = NULL docsactif-gtsauve = FALSE cb_save (p_widget user_data) if (docsactif-gtsauve) (docsactif) = tmp else print_warning (Aucun document ouvert)

Il ne faut pas oublier que lutilisateur peut annuler lenregistrement de ce fait nous sauvegardons leacutetat du documentet si la sauvegarde na pas eu lieu on le restaure

VIII-D - Code source

chapitre8zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 27 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IX - Creacuteer un nouveau document

IX-A - Aperccedilu

Cliquez pour agrandir

IX-B - Nouveau fichier

Maintenant que lutilisateur peut ouvrir et fermer un fichier il est inteacuteressant de lui donner la possibiliteacute den creacuteerun nouveau Je ne reviens pas sur la creacuteation du bouton (ccedila devrait deacutejagrave ecirctre fait D) passons directement agrave lafonction cb_new

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) Pour linstant il faut allouer la memoire par la suite on modifiera simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = NULL Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = GTK_TEXT_VIEW (user_data) Le document vient detre creer il nest donc pas modifie docsactif-gtsauve = TRUE gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Je ne sais pas vous mais pour ma part jai fait un copiercoller de la fonction open_file Et oui ouvrir un document peutse reacutesumer agrave creacuteer un document vide puis remplir le GtkTextView avec le fichier souhaiteacute On peut donc simplifiernotre fonction open_file ainsi

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

cb_new (NULL p_text_view) gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE) p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1) Nous sommes obliges de remetre sauve a TRUE car linsertion du contenu du fichier dans le GtkTextView a appele cb_modfie docsactif-gtsauve = TRUE else print_warning (Impossible douvrir le fichier sn file_name)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 28 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc

Cest beau la factorisation du code Par contre nous sommes obligeacutes de remettre sauve agrave TRUE car nous avonsmodifieacute le GtkTextBuffer

IX-C - Code source

chapitre9zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 29 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

X - Fermer

X-A - Aperccedilu

Cliquez pour agrandir

X-B - Fermer un fichier

Maintenant que nous allouons de la meacutemoire il faut la libeacuterer agrave un endroit Logiquement cela va ecirctre fait agrave la fermeturedu document en guise dexercice je vous laisse creacuteer le bouton dans notre boicircte agrave bouton

Allez je vous aide le stock id correspondant est GTK_STOCK_CLOSE

Voilagrave maintenant si tout cest bien passeacute vous devriez ecirctre arriveacute dans le fichier callbackc avec quelque choseressemblant agrave

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data)

Lorsque lon ferme un document il faut vider le GtkTextView (avec les onglets on se contentera de le supprimer)pour cela il faut reacutecupeacuterer le deacutebut et la fin du GtkTextBuffer et demander agrave GTK+ de supprimer tout ce qui ce trouveentre les deux iteacuterateurs

callbackc Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) gtk_text_buffer_delete (p_text_buffer ampstart ampend) else print_warning (Aucun document ouvert)

Bien sucircr il ne faut pas oublier de libeacuterer la meacutemoire

callbackc g_free (docsactif-gtchemin) docsactif-gtchemin = NULL docsactif-gtp_text_view = NULL g_free (docsactif) docsactif = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 30 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour symboliser la fermeture dun document nous deacutesactivons le GtkTextView lors de la fermeture (ne pas oublierde le faire aussi dans mainc)

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) FALSE)

Et nous le reacuteactivons lors de louverture si celle si reacuteussie

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Lorsque lutilisateur quitte lapplication il faut bien sucircr fermer le document sil y en a un ouvert

void cb_quit (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data) gtk_main_quit()

Et aussi lorsquil creacuteeacute un nouveau document (et par conseacutequent lorsquil ouvre un fichier puisque lon fait appel agravecb_new)

void cb_new (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data)

X-C - Enregistrer avant de fermer

Si le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde geacuteneacuteralement le programme le signale agrave lutilisateur etlui propose de sauvegarder ou dannuler la fermeture Pour se faire nous devons modifier la fonction cb_close avantde fermer le document nous allons afficher une boicircte de dialogue

Pour creacuteer une boicircte de dialogue simplement il existe la classe GtkDialog et comme nous avons besoin de boutons(pour que lutilisateur fasse son choix) nous allons creacuteer notre boicircte avec la fonction

GtkWidget gtk_dialog_new_with_buttons (const gchar title GtkWindow parent GtkDialogFlags flags const gchar first_button_text )

Nous retrouvons les mecircmes options que pour le GtkFileChooserDialog mis agrave part option du type GtkDialogFlags

typedef enum GTK_DIALOG_MODAL = 1 ltlt 0 appel gtk_window_set_modal (win TRUE) GTK_DIALOG_DESTROY_WITH_PARENT = 1 ltlt 1 appel gtk_window_set_destroy_with_parent () GTK_DIALOG_NO_SEPARATOR = 1 ltlt 2 Pas de barre de separation au dessus des boutons GtkDialogFlags

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 31 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Nous nous contenterons de rendre notre fenecirctre modale (7)

Pour avoir accegraves agrave notre fenecirctre principale nous ajoutons un champs p_main_window agrave notre structure globaledocs_t que nous initialisons dans la fonction main

mainc docsp_main_window = GTK_WINDOW (p_window)

Il nous reste plus qua creacuteer notre boicircte de dialogue avec trois boutons Oui Non Annuler

callbackc if (docsactif-gtsauve) GtkWidget p_dialog = NULL

p_dialog = gtk_dialog_new_with_buttons (Sauvegarder docsp_main_window GTK_DIALOG_MODAL GTK_STOCK_YES GTK_RESPONSE_YES GTK_STOCK_NO GTK_RESPONSE_NO GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL NULL)

Nous obtenons donc une structure de type GtkDialog

typedef struct GtkWidget vbox GtkWidget action_area GtkDialog

Nous remarquons que cette structure contient deux membres qui permettent dacceacuteder agrave une GtkBox ougrave nous allonsajouter le contenu de la fenecirctre et agrave la partie contenant les boutons

Ensuite la construction de la fenecirctre est identique agrave celle de la fenecirctre principale ici nous nous contenterons dajouterun GtkLabel

callbackc GtkWidget p_label = NULL p_label = gtk_label_new (Voulez-vous sauvegarder les modifications ) gtk_box_pack_start (GTK_BOX (GTK_DIALOG (p_dialog)-gtvbox) p_label TRUE TRUE 0)

Une fois notre fenecirctre precircte il suffit de faire appel agrave la fonction gtk_dialog_run qui va afficher notre GtkDialog et nousretourner le reacuteponse id correspondant au bouton cliqueacute par lutilisateur

callbackc switch (gtk_dialog_run (GTK_DIALOG (p_dialog))) case GTK_RESPONSE_YES cb_save (p_widget user_data) break case GTK_RESPONSE_NO break case GTK_RESPONSE_CANCEL gtk_widget_destroy (p_dialog) return break

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 32 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc gtk_widget_destroy (p_dialog)

Si lutilisateur clique sur non on ne fait rien (le document sera simplement fermeacute) sur oui on enregistre avant defermer et pour finir sil annule on quitte la fonction

X-D - Code source

chapitre10zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 33 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XI - Les barres de deacutefilement

XI-A - Aperccedilu

Cliquez pour agrandir

XI-B - Ajouter des barres de deacutefilement

Apregraves le dernier chapitre quelque peu laborieux voici une partie plus simple mais qui va rendre notre applicationplus pratique En effet si vous avez essayeacute douvrir un fichier de grande taille vous avez pu remarquer que pourpouvoir lire la fin du fichier il fallait utiliser les touches du clavier pas tregraves convivial

Pour rendre la navigation plus aiseacutee on utilise des barres de deacutefilement

mainc GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_scrolled_window TRUE TRUE 0)

Creation de la zone de texte gtk_container_add (GTK_CONTAINER (p_scrolled_window) p_text_view)

Le constructeur de notre GtkScrolledWindow prend en argument deux GtkAdjustment qui permettent de deacutefinirdiffeacuterentes proprieacuteteacutes de la barre de deacutefilement (taille dune page la position de deacutepart) nous laissons GTK+ faireen passant NULL

Cest un bon deacutebut mais estheacutetiquement on peut faire mieux mecircme sil nest pas utile davoir une barre de deacutefilementelle est quand mecircme afficheacutee On peut demander agrave GTK+ de les afficher que si cela est neacutecessaire

mainc gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC)

En fait nous avons de la chance car la classe GtkTextView fait partie des widget qui supporte de faccedilon native les barresde deacutefilement Comment le savoir Ce genre de widget possegravede une ou deux proprieacuteteacutes de type GtkAdjustment (unepour la barre verticale lautre pour la barre horizontale) Actuellement seulement trois classes en sont capables lesGtkTextView les GtkTreeView et les GtkLayout

Comment faire pour les autres widgets Il faut passer par une classe adaptateur GtkViewport afin de creacuteer lesGtkAdjustment

XI-C - Code source

chapitre11zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 34 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XII - Les menus

XII-A - Aperccedilu

Cliquez pour agrandir

XII-B - Creacuteation du menu

Pour simplifier nous avons utiliseacute des boutons pour permettre agrave lutilisateur de creacuteer un document ouvrir un fichierMais il est plus courant dutiliser un menu pour afficher ces options GTK+ propose trois maniegraveres de creacuteer un menu

bull GtkItemFactory cette meacutethode est obsolegravete depuis la version 24 de GTK+

bull GtkUIManager cest ce quon appel une usine agrave gaz pour en savoir plus vous pouvez vous reporter aututoriel Utilisation de GtkUIManager

bull GtkMenu cest ce widget que nous allons eacutetudier il permet de creacuteer un menu manuellement (agrave lopposeacute deGtkUIManager)

Un menu selon GTK+ est composeacute de plusieurs eacuteleacutements

bull GtkMenuBar la barre de menu elle-mecircme

bull GtkMenu la partie deacuteroulante qui contient les diffeacuterents eacuteleacutements

bull GtkMenuItem cest sur ce widget que lutilisateur clique pour lancer une action

Pour commencer faisons linventaire de ce que nous avons besoin

bull Un GtkMenuBar qui sert de base au menu

bull Un GtkMenu pour commencer nous nous aurons dun menu Fichier

bull Six GtkMenuItem pour remplacer nos six boutons

Commenccedilons par la creacuteation du menu nous mettons ce code dans un nouveau fichier dont seul la fonction menu_newsera accessible

menucGtkMenuBar menu_new (gpointer user_data) GtkWidget p_menu_bar = NULL

p_menu_bar = gtk_menu_bar_new () return GTK_MENU_BAR (p_menu_bar)

Le paramegravetre user_data nous servira lors de la connexion des callbacks (nous en avons besoin pour les fonctionscb_new et cb_open)

Ensuite nous allons creacuteer notre sous menu Fichier

menuc Menu Fichier

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 35 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

menuc GtkWidget p_menu = NULL GtkWidget p_menu_item = NULL

p_menu = gtk_menu_new () p_menu_item = gtk_menu_item_new_with_mnemonic (_Fichier) gtk_menu_item_set_submenu (GTK_MENU_ITEM (p_menu_item) p_menu) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu_bar) p_menu_item) return GTK_MENU_BAR (p_menu_bar)

Un sous menu est en fait un GtkMenuItem auquel on assigne un GtkMenu Il faut bien sucircr terminer la creacuteation dusous-menu en lajoutant agrave la barre de menu

Pour finir nous creacuteons les eacuteleacutements du menu les GtkItemMenu Il existe plusieurs types deacuteleacutements (comparableaux diffeacuterents types de bouton) pour commencer nous nutiliserons que le type de base Comme cette opeacuteration estreacutepeacutetitive nous allons creacuteer une fonction pour le faire

menucstatic void menu_item_new (GtkMenu p_menu const gchar title GCallback callback gpointer user_data) GtkWidget p_menu_item = NULL

p_menu_item = gtk_menu_item_new_with_mnemonic (title) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu) p_menu_item) g_signal_connect (G_OBJECT (p_menu_item) activate callback user_data)

Pour permettre agrave lutilisateur dacceacuteder aux diffeacuterents eacuteleacutements du menu agrave laide de la touche ltAltgt nous utilisonsdes mneacutemoniques par exemple pour quitter leacutediteur il suffit de faite Alt+F puis Q Et voici le code pour creacuteer nossix eacuteleacutements du menu

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau G_CALLBACK (cb_new) user_data) menu_item_new (GTK_MENU (p_menu) _Ouvrir G_CALLBACK (cb_open) user_data) menu_item_new (GTK_MENU (p_menu) _Enregistrer G_CALLBACK (cb_save) user_data) menu_item_new (GTK_MENU (p_menu) Enregistrer _sous G_CALLBACK (cb_saveas) user_data) menu_item_new (GTK_MENU (p_menu) _Fermer G_CALLBACK (cb_close) user_data) menu_item_new (GTK_MENU (p_menu) _Quitter G_CALLBACK (cb_quit) user_data)

Voilagrave notre menu est creacuteeacute il nous reste plus quagrave linteacutegrer agrave notre fenecirctre

mainc gtk_box_pack_start (GTK_BOX (p_main_box) GTK_WIDGET (menu_new (p_text_view)) FALSE FALSE 0)

Le problegraveme cest que nous avons besoin de passer le GtkTextView lors de la creacuteation du menu (qui est utiliseacute par lesfonctions cb_new et cb_open) or celui-ci est creacuteeacute apregraves le menu (puisque nous creacuteons les widgets dans lordre ougrave ilfaut les inteacutegrer agrave linterface (8) ) nous devons creacuteer le GtkTextView (seul lappel agrave gtk_text_view_new est deacuteplaceacute)

XII-C - Code source

chapitre12zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 36 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIII - Les barres doutils

XIII-A - Aperccedilu

Cliquez pour agrandir

XIII-B - Creacuteation dune barre doutils

La creacuteation dune barre doutils ressemble fort agrave celle dun menu en plus simple puisquil ny a pas de sous menu on creacutee notre barre doutils (gtk_toolbar_new) puis les eacuteleacutements de la barre pour cela on utilise des boutons(gtk_tool_button_new_from_stock) que lon inseacutere dans la barre (gtk_toolbar_insert) Pas conseacutequent notre fichierbarreoutilsc ressemble agrave menuc

barreoutilscinclude ltgtkgtkhgtinclude callbackhinclude barreoutilsh

static void toolbar_item_new (GtkToolbar const gchar GCallback gpointer)

GtkToolbar toolbar_new (gpointer user_data) GtkWidget p_toolbar = NULL

p_toolbar = gtk_toolbar_new () toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_NEW G_CALLBACK (cb_new) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_OPEN G_CALLBACK (cb_open) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE G_CALLBACK (cb_save) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE_AS G_CALLBACK (cb_saveas) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_CLOSE G_CALLBACK (cb_close) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_QUIT G_CALLBACK (cb_quit) user_data) return GTK_TOOLBAR (p_toolbar)

static void toolbar_item_new (GtkToolbar p_toolbar const gchar stock_id GCallback callback gpointer user_data) GtkToolItem p_tool_item = NULL

p_tool_item = gtk_tool_button_new_from_stock (stock_id) g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data) gtk_toolbar_insert (p_toolbar p_tool_item -1)

Le code nest pas complet car lorsque jexeacutecute le programme GTK+ affiche en plus des icocircnes le texte sous lesboutons Pour modifier cela il suffit dajouter une ligne de code

barreoutilsc gtk_toolbar_set_style (GTK_TOOLBAR (p_toolbar) GTK_TOOLBAR_ICONS)

Pourquoi gtk_tool_button_new_from_stock retourne un GtkToolItem et non un GtkWidgetcomme nous avons eacuteteacute habitueacute jusquagrave preacutesent Il sagit dune bizarrerie de GTK+ dontje ne connais pas la raison

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 37 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour anticiper un changement dinterface (dans GTK+ 30 peut ecirctre ) nous aurions pueacutecrire

Gtkwidget p_tool_item = NULL

p_tool_item = GTK_WIDGET (gtk_tool_button_new_from_stock (stock_id))g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data)gtk_toolbar_insert (p_toolbar GTK_TOOL_ITEM (p_tool_item) -1)

XIII-C - Code source

chapitre13zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 38 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIV - Les racourcis clavier

XIV-A - Aperccedilu

Cliquez pour agrandir

XIV-B - Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mneacutemoniques ces derniers permettent dacceacuteder agrave un eacuteleacutementseacutequentiellement alors que les raccourcis appellent une fonction si lutilisateur appuie simultaneacutement sur une ouplusieurs touches (geacuteneacuteralement de la forme ltModificateurgtTouche ougrave Modificateur repreacutesente les touches ShiftAlt et Control) Ce raccourci peut ecirctre attacheacute agrave un eacuteleacutement du menu mais ceci nest pas obligatoire

Les raccourcis sont regroupeacutes en groupe dans un GtkAccelGroup quil faut commencer par creacuteer

raccourciscinclude ltgtkgtkhgtinclude callbackhinclude raccourcish

GtkAccelGroup accel_group_new (gpointer user_data) GtkAccelGroup p_accel_group = NULL

p_accel_group = gtk_accel_group_new () return p_accel_group

Vous commencez agrave avoir lhabitude de cette organisation nous allons donc creacuteer une fonction qui va se chargerdajouter un raccourci au groupe

raccourciscstatic void accelerator_new (GtkAccelGroup p_accel_group const gchar accelerator const gchar accel_path GCallback callback gpointer user_data) guint key GdkModifierType mods GClosure closure = NULL

gtk_accelerator_parse (accelerator ampkey ampmods) closure = g_cclosure_new (callback user_data NULL) gtk_accel_group_connect (p_accel_group key mods GTK_ACCEL_VISIBLE closure) gtk_accel_map_add_entry (accel_path key mods)

La fonction gtk_accelerator_parse permet de deacutecomposer une chaicircne de caractegraveres de la forme ltControlgtF1 ouencore ltAltgtA en numeacutero de touche et modificateur

En plus des touches pour creacuteer un raccourci clavier nous avons besoin dune fonction agrave appeler lorsque lutilisateurappuie sur les touches speacutecifieacutees gtk_accel_group_connect attend une fonction du type GClosure regardons ladocumentation de gobject pour savoir agrave quoi cela correspond

typedef struct

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 20 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VI - Choisir un fichier

VI-A - Aperccedilu

Cliquez pour agrandir

VI-B - Utilisation dun GtkFileChooserFile

Jusquagrave preacutesent lutilisateur navait pas le choix quant au fichier agrave ouvrir heureusement GTK+ vient agrave notre aide gracircceau widget GtkFileChooserFile qui est tout simplement une boicircte de dialogue qui propose agrave lutilisateur de seacutelectionnerun fichier dans son arborescence disque

Commenccedilons par creacuteer notre boicircte de dialogue dans la fonction cb_open

callbackcvoid cb_open (GtkWidget p_widget gpointer user_data) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Ouvrir un fichier NULL GTK_FILE_CHOOSER_ACTION_OPEN GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_OPEN GTK_RESPONSE_ACCEPT NULL)

Cette fonction neacutecessite le titre de la boicircte de dialogue une fenecirctre parente le type daction (ici on souhaite ouvrir unfichier GTK+ autorisera lutilisateur agrave seacutelectionner uniquement les fichiers existants) Pour finir il sagit dun couple devaleurs GTK_STOCK_ITEMGTK_STOCK_RESPONSE qui permet de creacuteer un bouton utilisant le stock ID speacutecifieacuteet lorsque celui-ci est cliqueacute la fonction servant agrave lancer la boicircte de dialogue retournera le reacuteponse ID correspondantIl existe une seacuterie de valeurs deacutefinies par GTK+ quil est conseilleacute dutiliser

typedef enum GTK returns this if a response widget has no response_id or if the dialog gets programmatically hidden or destroyed GTK_RESPONSE_NONE = -1

GTK wont return these unless you pass them in as the response for an action widget They are for your convenience GTK_RESPONSE_REJECT = -2 GTK_RESPONSE_ACCEPT = -3

If the dialog is deleted GTK_RESPONSE_DELETE_EVENT = -4

These are returned from GTK dialogs and you can also use them yourself if you like GTK_RESPONSE_OK = -5 GTK_RESPONSE_CANCEL = -6 GTK_RESPONSE_CLOSE = -7 GTK_RESPONSE_YES = -8

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 21 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GTK_RESPONSE_NO = -9 GTK_RESPONSE_APPLY = -10 GTK_RESPONSE_HELP = -11 GtkResponseType

Nous indiquons la fin des couples stock idreacuteponse id avec la valeur NULL

Une fois la boicircte de dialogue creacuteee on demande agrave GTK+ de lafficher gracircce agrave la fonction gtk_dialog_run puis onreacutecupegravere sa valeur de retour qui correspond au bouton cliqueacute par lutilisateur

callbackc if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

Ici ce qui nous inteacuteresse cest lorsque que lutilisateur clique sur le bouton ouvrir (donc gtk_dialog_run renvoieGTK_RESPONSE_ACCEPT) dans ce cas il nous suffit de reacutecupeacuterer le nom du fichier seacutelectionneacute puis de louvrir

callbackc gchar file_name = NULL

file_name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) open_file (file_name GTK_TEXT_VIEW (user_data)) g_free (file_name) file_name = NULL

Pour finir dans tous les cas on noublie pas de deacutetruire la boicircte de dialogue

callbackc gtk_widget_destroy (p_dialog)

Et voilagrave le travail lutilisateur peut ouvrir le fichier quil souhaite

VI-C - Code source

chapitre6zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 22 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VII - Interlude

Avant daller plus loin dans lameacutelioration de linterface de notre eacutediteur il est neacutecessaire de modifier sonfonctionnement interne (ne vous inquieacutetez je nai pas dit chambouler) en effet souvenez-vous dans lintroduction jaieacutevoqueacute la possibiliteacutes douvrir plusieurs documents gracircce agrave un systegraveme donglets Pour cela il faut sauvegarder lesproprieacuteteacutes de chaque document ouvert Pris agrave temps ce genre de modification nest pas trop lourde mais si nousattendons cela risque de devenir un vrai casse tecircte

Pour cela nous allons utiliser une structure de donneacutee pour chaque document ouvert qui devra garder en meacutemoirele chemin complet du fichier (ou NULL si le document nest pas encore sauvegarder) sil agrave eacutetait modifier depuis laderniegravere sauvegarde et le GtkTextView qui sert agrave son affichage Voici donc la structure qui va nous servir

documenthtypedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

Sachant que nous serons ameneacute agrave stocker plusieurs occurrences de cette structure il serait bon de reacutefleacutechir degravesmaintenant agrave la structure de donneacutee agrave utiliser pour les stocker La premiegravere ideacutee qui vient agrave lesprit est un tableaualloueacute dynamiquement cependant lutilisateur peut souhaiter fermer un document qui se trouve au milieu on estalors obligeacute de deacutecaler toutes les cellules en amont Dans ce cas il parait naturel dutiliser une liste chaicircneacutee Parchance la glib propose une bibliothegraveque de gestion des listes chaicircneacutees cela nous fera gagner du temps le momentvenu Pour linstant on se contente de creacuteer une structure de donneacutees qui contiendra tous les documents ouverts(stockeacutee dans une GList) et un pointeur sur le document actif (actuellement comme nous navons quun documentouvert en mecircme temps on manipulera uniquement ce pointeur)

documenthtypedef struct GList tous document_t actif docs_t

Maintenant se pose le problegraveme de savoir comment transmettre cette structure On pourrait se servir du paramegravetreuser_data preacutesent dans toutes les fonctions callback mais certaines fonctions utilise deacutejagrave ce paramegravetre (la fonctioncb_open par exemple) il faudrait creacuteer un champs suppleacutementaire dans notre structure documents_s Une solutionplus simple est de creacuteer une variable globale agrave lensemble du programme Ceux qui passe reacuteguliegraverement sur le forumC savent que cest fortement deacuteconseilleacute mais ici nous nous trouvons dans lune des rares exceptions agrave la regravegle Detoute faccedilon cela revient au mecircme que de passer ladresse de notre structure agrave toutes les fonctions callback Nousdeacutefinissons donc un nouveau fichier den-tecircte

documenthifndef H_DOCUMENTdefine H_DOCUMENT

include ltgtkgtkhgt

typedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 23 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

documenthtypedef struct GList tous document_t actif docs_t

extern docs_t docs

endif not H_DOCUMENT

Et dans le fichier mainc

maincinclude documenth

docs_t docs = NULL NULL

Pour linstant la seule fonction qui modifie leacutetat dun document est la fonction open_file il faut donc inclure documenthdans callbackc et modifier leacutegegraverement la fonction pour enregistrer le document ouvert

callbackc if (g_file_get_contents (file_name ampcontents NULL NULL)) Pour linstant il faut allouer la memoire par la suite on modifira simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = g_strdup (file_name) Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = p_text_view Le document vient detre ouvert il nest donc pas modifie docsactif-gtsauve = TRUE

Ne soyez pas choqueacute si je ne teste pas le retour de la fonction g_malloc pour veacuterifier quilnest pas NULL En effet cette derniegravere met fin agrave lapplication si lallocation eacutechoue

VII-A - Code source

chapitre7zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 24 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VIII - Sauvegarder les modification

VIII-A - Aperccedilu

Cliquez pour agrandir

VIII-B - Enregistrer

Avant de pouvoir sauvegarder un document il faut quil soit modifieacute Comment savoir que le contenu du fichier a eacuteteacutemodifier Gracircce au signal changed du GtkTextBuffer que nous interceptons gracircce agrave la fonction cb_modifie

mainc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (p_text_view)) g_signal_connect (G_OBJECT (p_text_buffer) changed G_CALLBACK (cb_modifie) NULL)

Cette derniegravere modifie simplement le champ sauve du document

callbackcvoid cb_modifie (GtkWidget p_widget gpointer user_data) if (docsactif) docsactif-gtsauve = FALSE

Pour la sauvegarde il faut distinguer deux cas soit il sagit de la premiegravere sauvegarde du fichier il faut alors demanderle nom du fichier agrave lutilisateur (cela ressemble fortement agrave louverture dun fichier) soit le fichier est deacutejagrave preacutesent surle disque il suffit de remplacer son contenu par celui du GtkTextViewer Nous avons convenu quun fichier qui neacutetaitpas encore enregistreacute avait sa proprieacuteteacute chemin agrave NULL

Bien sucircr cela na lieu que si un fichier est ouvert et quil a eacuteteacute modifieacute depuis sa derniegravere sauvegarde

callbackcvoid cb_save (GtkWidget p_widget gpointer user_data) if (docsactif) if (docsactif-gtsauve) Le fichier na pas encore ete enregistre if (docsactif-gtchemin) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Sauvegarder le fichier NULL GTK_FILE_CHOOSER_ACTION_SAVE GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_SAVE GTK_RESPONSE_ACCEPT NULL) if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 25 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc docsactif-gtchemin = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) gtk_widget_destroy (p_dialog) Soit le fichier a deja ete enregistre soit lutilisateur vient de nous fournir son nouvel enplacement on peut donc lenregistrer if (docsactif-gtchemin) else print_warning (Aucun document ouvert)

Il nous reste plus quagrave reacutecupeacuterer le contenu du GtkTextViewer et le copier dans le fichier chemin sans oublier dereconvertir le texte dans le codage local

callbackc FILE fichier = NULL

fichier = fopen (docsactif-gtchemin w) if (fichier) gchar contents = NULL gchar locale = NULL GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) contents = gtk_text_buffer_get_text (p_text_buffer ampstart ampend FALSE) locale = g_locale_from_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL fprintf (fichier s locale) g_free (locale) locale = NULL fclose (fichier) fichier = NULL docsactif-gtsauve = TRUE else print_warning (Impossible de sauvegarder le fichier s docsactif-gtchemin)

Le dernier paramegravetre de la fonction gtk_text_buffer_get_text est mis agrave FALSE car nous ne voulons pas enregistrerles caractegraveres invisibles preacutesent dans le GtkTextBuffer Ces caractegraveres servent agrave mettre en forme le texte (taillecouleur) nous pourrions creacuteer un nouveau format de fichier pour enregistrer la mise en forme

VIII-C - Enregistrer sous

Pour enregistrer notre document sous un autre nom il suffit de faire croire agrave cb_save que le document na pas encoreeacutetait enregistreacute tout simplement en changeant chemin agrave NULL et sauve agrave FALSE

callbackcvoid cb_saveas (GtkWidget p_widget gpointer user_data)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 26 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (docsactif) document_t tmp = docsactif

docsactif-gtchemin = NULL docsactif-gtsauve = FALSE cb_save (p_widget user_data) if (docsactif-gtsauve) (docsactif) = tmp else print_warning (Aucun document ouvert)

Il ne faut pas oublier que lutilisateur peut annuler lenregistrement de ce fait nous sauvegardons leacutetat du documentet si la sauvegarde na pas eu lieu on le restaure

VIII-D - Code source

chapitre8zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 27 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IX - Creacuteer un nouveau document

IX-A - Aperccedilu

Cliquez pour agrandir

IX-B - Nouveau fichier

Maintenant que lutilisateur peut ouvrir et fermer un fichier il est inteacuteressant de lui donner la possibiliteacute den creacuteerun nouveau Je ne reviens pas sur la creacuteation du bouton (ccedila devrait deacutejagrave ecirctre fait D) passons directement agrave lafonction cb_new

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) Pour linstant il faut allouer la memoire par la suite on modifiera simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = NULL Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = GTK_TEXT_VIEW (user_data) Le document vient detre creer il nest donc pas modifie docsactif-gtsauve = TRUE gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Je ne sais pas vous mais pour ma part jai fait un copiercoller de la fonction open_file Et oui ouvrir un document peutse reacutesumer agrave creacuteer un document vide puis remplir le GtkTextView avec le fichier souhaiteacute On peut donc simplifiernotre fonction open_file ainsi

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

cb_new (NULL p_text_view) gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE) p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1) Nous sommes obliges de remetre sauve a TRUE car linsertion du contenu du fichier dans le GtkTextView a appele cb_modfie docsactif-gtsauve = TRUE else print_warning (Impossible douvrir le fichier sn file_name)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 28 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc

Cest beau la factorisation du code Par contre nous sommes obligeacutes de remettre sauve agrave TRUE car nous avonsmodifieacute le GtkTextBuffer

IX-C - Code source

chapitre9zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 29 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

X - Fermer

X-A - Aperccedilu

Cliquez pour agrandir

X-B - Fermer un fichier

Maintenant que nous allouons de la meacutemoire il faut la libeacuterer agrave un endroit Logiquement cela va ecirctre fait agrave la fermeturedu document en guise dexercice je vous laisse creacuteer le bouton dans notre boicircte agrave bouton

Allez je vous aide le stock id correspondant est GTK_STOCK_CLOSE

Voilagrave maintenant si tout cest bien passeacute vous devriez ecirctre arriveacute dans le fichier callbackc avec quelque choseressemblant agrave

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data)

Lorsque lon ferme un document il faut vider le GtkTextView (avec les onglets on se contentera de le supprimer)pour cela il faut reacutecupeacuterer le deacutebut et la fin du GtkTextBuffer et demander agrave GTK+ de supprimer tout ce qui ce trouveentre les deux iteacuterateurs

callbackc Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) gtk_text_buffer_delete (p_text_buffer ampstart ampend) else print_warning (Aucun document ouvert)

Bien sucircr il ne faut pas oublier de libeacuterer la meacutemoire

callbackc g_free (docsactif-gtchemin) docsactif-gtchemin = NULL docsactif-gtp_text_view = NULL g_free (docsactif) docsactif = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 30 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour symboliser la fermeture dun document nous deacutesactivons le GtkTextView lors de la fermeture (ne pas oublierde le faire aussi dans mainc)

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) FALSE)

Et nous le reacuteactivons lors de louverture si celle si reacuteussie

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Lorsque lutilisateur quitte lapplication il faut bien sucircr fermer le document sil y en a un ouvert

void cb_quit (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data) gtk_main_quit()

Et aussi lorsquil creacuteeacute un nouveau document (et par conseacutequent lorsquil ouvre un fichier puisque lon fait appel agravecb_new)

void cb_new (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data)

X-C - Enregistrer avant de fermer

Si le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde geacuteneacuteralement le programme le signale agrave lutilisateur etlui propose de sauvegarder ou dannuler la fermeture Pour se faire nous devons modifier la fonction cb_close avantde fermer le document nous allons afficher une boicircte de dialogue

Pour creacuteer une boicircte de dialogue simplement il existe la classe GtkDialog et comme nous avons besoin de boutons(pour que lutilisateur fasse son choix) nous allons creacuteer notre boicircte avec la fonction

GtkWidget gtk_dialog_new_with_buttons (const gchar title GtkWindow parent GtkDialogFlags flags const gchar first_button_text )

Nous retrouvons les mecircmes options que pour le GtkFileChooserDialog mis agrave part option du type GtkDialogFlags

typedef enum GTK_DIALOG_MODAL = 1 ltlt 0 appel gtk_window_set_modal (win TRUE) GTK_DIALOG_DESTROY_WITH_PARENT = 1 ltlt 1 appel gtk_window_set_destroy_with_parent () GTK_DIALOG_NO_SEPARATOR = 1 ltlt 2 Pas de barre de separation au dessus des boutons GtkDialogFlags

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 31 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Nous nous contenterons de rendre notre fenecirctre modale (7)

Pour avoir accegraves agrave notre fenecirctre principale nous ajoutons un champs p_main_window agrave notre structure globaledocs_t que nous initialisons dans la fonction main

mainc docsp_main_window = GTK_WINDOW (p_window)

Il nous reste plus qua creacuteer notre boicircte de dialogue avec trois boutons Oui Non Annuler

callbackc if (docsactif-gtsauve) GtkWidget p_dialog = NULL

p_dialog = gtk_dialog_new_with_buttons (Sauvegarder docsp_main_window GTK_DIALOG_MODAL GTK_STOCK_YES GTK_RESPONSE_YES GTK_STOCK_NO GTK_RESPONSE_NO GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL NULL)

Nous obtenons donc une structure de type GtkDialog

typedef struct GtkWidget vbox GtkWidget action_area GtkDialog

Nous remarquons que cette structure contient deux membres qui permettent dacceacuteder agrave une GtkBox ougrave nous allonsajouter le contenu de la fenecirctre et agrave la partie contenant les boutons

Ensuite la construction de la fenecirctre est identique agrave celle de la fenecirctre principale ici nous nous contenterons dajouterun GtkLabel

callbackc GtkWidget p_label = NULL p_label = gtk_label_new (Voulez-vous sauvegarder les modifications ) gtk_box_pack_start (GTK_BOX (GTK_DIALOG (p_dialog)-gtvbox) p_label TRUE TRUE 0)

Une fois notre fenecirctre precircte il suffit de faire appel agrave la fonction gtk_dialog_run qui va afficher notre GtkDialog et nousretourner le reacuteponse id correspondant au bouton cliqueacute par lutilisateur

callbackc switch (gtk_dialog_run (GTK_DIALOG (p_dialog))) case GTK_RESPONSE_YES cb_save (p_widget user_data) break case GTK_RESPONSE_NO break case GTK_RESPONSE_CANCEL gtk_widget_destroy (p_dialog) return break

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 32 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc gtk_widget_destroy (p_dialog)

Si lutilisateur clique sur non on ne fait rien (le document sera simplement fermeacute) sur oui on enregistre avant defermer et pour finir sil annule on quitte la fonction

X-D - Code source

chapitre10zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 33 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XI - Les barres de deacutefilement

XI-A - Aperccedilu

Cliquez pour agrandir

XI-B - Ajouter des barres de deacutefilement

Apregraves le dernier chapitre quelque peu laborieux voici une partie plus simple mais qui va rendre notre applicationplus pratique En effet si vous avez essayeacute douvrir un fichier de grande taille vous avez pu remarquer que pourpouvoir lire la fin du fichier il fallait utiliser les touches du clavier pas tregraves convivial

Pour rendre la navigation plus aiseacutee on utilise des barres de deacutefilement

mainc GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_scrolled_window TRUE TRUE 0)

Creation de la zone de texte gtk_container_add (GTK_CONTAINER (p_scrolled_window) p_text_view)

Le constructeur de notre GtkScrolledWindow prend en argument deux GtkAdjustment qui permettent de deacutefinirdiffeacuterentes proprieacuteteacutes de la barre de deacutefilement (taille dune page la position de deacutepart) nous laissons GTK+ faireen passant NULL

Cest un bon deacutebut mais estheacutetiquement on peut faire mieux mecircme sil nest pas utile davoir une barre de deacutefilementelle est quand mecircme afficheacutee On peut demander agrave GTK+ de les afficher que si cela est neacutecessaire

mainc gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC)

En fait nous avons de la chance car la classe GtkTextView fait partie des widget qui supporte de faccedilon native les barresde deacutefilement Comment le savoir Ce genre de widget possegravede une ou deux proprieacuteteacutes de type GtkAdjustment (unepour la barre verticale lautre pour la barre horizontale) Actuellement seulement trois classes en sont capables lesGtkTextView les GtkTreeView et les GtkLayout

Comment faire pour les autres widgets Il faut passer par une classe adaptateur GtkViewport afin de creacuteer lesGtkAdjustment

XI-C - Code source

chapitre11zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 34 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XII - Les menus

XII-A - Aperccedilu

Cliquez pour agrandir

XII-B - Creacuteation du menu

Pour simplifier nous avons utiliseacute des boutons pour permettre agrave lutilisateur de creacuteer un document ouvrir un fichierMais il est plus courant dutiliser un menu pour afficher ces options GTK+ propose trois maniegraveres de creacuteer un menu

bull GtkItemFactory cette meacutethode est obsolegravete depuis la version 24 de GTK+

bull GtkUIManager cest ce quon appel une usine agrave gaz pour en savoir plus vous pouvez vous reporter aututoriel Utilisation de GtkUIManager

bull GtkMenu cest ce widget que nous allons eacutetudier il permet de creacuteer un menu manuellement (agrave lopposeacute deGtkUIManager)

Un menu selon GTK+ est composeacute de plusieurs eacuteleacutements

bull GtkMenuBar la barre de menu elle-mecircme

bull GtkMenu la partie deacuteroulante qui contient les diffeacuterents eacuteleacutements

bull GtkMenuItem cest sur ce widget que lutilisateur clique pour lancer une action

Pour commencer faisons linventaire de ce que nous avons besoin

bull Un GtkMenuBar qui sert de base au menu

bull Un GtkMenu pour commencer nous nous aurons dun menu Fichier

bull Six GtkMenuItem pour remplacer nos six boutons

Commenccedilons par la creacuteation du menu nous mettons ce code dans un nouveau fichier dont seul la fonction menu_newsera accessible

menucGtkMenuBar menu_new (gpointer user_data) GtkWidget p_menu_bar = NULL

p_menu_bar = gtk_menu_bar_new () return GTK_MENU_BAR (p_menu_bar)

Le paramegravetre user_data nous servira lors de la connexion des callbacks (nous en avons besoin pour les fonctionscb_new et cb_open)

Ensuite nous allons creacuteer notre sous menu Fichier

menuc Menu Fichier

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 35 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

menuc GtkWidget p_menu = NULL GtkWidget p_menu_item = NULL

p_menu = gtk_menu_new () p_menu_item = gtk_menu_item_new_with_mnemonic (_Fichier) gtk_menu_item_set_submenu (GTK_MENU_ITEM (p_menu_item) p_menu) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu_bar) p_menu_item) return GTK_MENU_BAR (p_menu_bar)

Un sous menu est en fait un GtkMenuItem auquel on assigne un GtkMenu Il faut bien sucircr terminer la creacuteation dusous-menu en lajoutant agrave la barre de menu

Pour finir nous creacuteons les eacuteleacutements du menu les GtkItemMenu Il existe plusieurs types deacuteleacutements (comparableaux diffeacuterents types de bouton) pour commencer nous nutiliserons que le type de base Comme cette opeacuteration estreacutepeacutetitive nous allons creacuteer une fonction pour le faire

menucstatic void menu_item_new (GtkMenu p_menu const gchar title GCallback callback gpointer user_data) GtkWidget p_menu_item = NULL

p_menu_item = gtk_menu_item_new_with_mnemonic (title) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu) p_menu_item) g_signal_connect (G_OBJECT (p_menu_item) activate callback user_data)

Pour permettre agrave lutilisateur dacceacuteder aux diffeacuterents eacuteleacutements du menu agrave laide de la touche ltAltgt nous utilisonsdes mneacutemoniques par exemple pour quitter leacutediteur il suffit de faite Alt+F puis Q Et voici le code pour creacuteer nossix eacuteleacutements du menu

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau G_CALLBACK (cb_new) user_data) menu_item_new (GTK_MENU (p_menu) _Ouvrir G_CALLBACK (cb_open) user_data) menu_item_new (GTK_MENU (p_menu) _Enregistrer G_CALLBACK (cb_save) user_data) menu_item_new (GTK_MENU (p_menu) Enregistrer _sous G_CALLBACK (cb_saveas) user_data) menu_item_new (GTK_MENU (p_menu) _Fermer G_CALLBACK (cb_close) user_data) menu_item_new (GTK_MENU (p_menu) _Quitter G_CALLBACK (cb_quit) user_data)

Voilagrave notre menu est creacuteeacute il nous reste plus quagrave linteacutegrer agrave notre fenecirctre

mainc gtk_box_pack_start (GTK_BOX (p_main_box) GTK_WIDGET (menu_new (p_text_view)) FALSE FALSE 0)

Le problegraveme cest que nous avons besoin de passer le GtkTextView lors de la creacuteation du menu (qui est utiliseacute par lesfonctions cb_new et cb_open) or celui-ci est creacuteeacute apregraves le menu (puisque nous creacuteons les widgets dans lordre ougrave ilfaut les inteacutegrer agrave linterface (8) ) nous devons creacuteer le GtkTextView (seul lappel agrave gtk_text_view_new est deacuteplaceacute)

XII-C - Code source

chapitre12zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 36 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIII - Les barres doutils

XIII-A - Aperccedilu

Cliquez pour agrandir

XIII-B - Creacuteation dune barre doutils

La creacuteation dune barre doutils ressemble fort agrave celle dun menu en plus simple puisquil ny a pas de sous menu on creacutee notre barre doutils (gtk_toolbar_new) puis les eacuteleacutements de la barre pour cela on utilise des boutons(gtk_tool_button_new_from_stock) que lon inseacutere dans la barre (gtk_toolbar_insert) Pas conseacutequent notre fichierbarreoutilsc ressemble agrave menuc

barreoutilscinclude ltgtkgtkhgtinclude callbackhinclude barreoutilsh

static void toolbar_item_new (GtkToolbar const gchar GCallback gpointer)

GtkToolbar toolbar_new (gpointer user_data) GtkWidget p_toolbar = NULL

p_toolbar = gtk_toolbar_new () toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_NEW G_CALLBACK (cb_new) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_OPEN G_CALLBACK (cb_open) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE G_CALLBACK (cb_save) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE_AS G_CALLBACK (cb_saveas) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_CLOSE G_CALLBACK (cb_close) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_QUIT G_CALLBACK (cb_quit) user_data) return GTK_TOOLBAR (p_toolbar)

static void toolbar_item_new (GtkToolbar p_toolbar const gchar stock_id GCallback callback gpointer user_data) GtkToolItem p_tool_item = NULL

p_tool_item = gtk_tool_button_new_from_stock (stock_id) g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data) gtk_toolbar_insert (p_toolbar p_tool_item -1)

Le code nest pas complet car lorsque jexeacutecute le programme GTK+ affiche en plus des icocircnes le texte sous lesboutons Pour modifier cela il suffit dajouter une ligne de code

barreoutilsc gtk_toolbar_set_style (GTK_TOOLBAR (p_toolbar) GTK_TOOLBAR_ICONS)

Pourquoi gtk_tool_button_new_from_stock retourne un GtkToolItem et non un GtkWidgetcomme nous avons eacuteteacute habitueacute jusquagrave preacutesent Il sagit dune bizarrerie de GTK+ dontje ne connais pas la raison

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 37 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour anticiper un changement dinterface (dans GTK+ 30 peut ecirctre ) nous aurions pueacutecrire

Gtkwidget p_tool_item = NULL

p_tool_item = GTK_WIDGET (gtk_tool_button_new_from_stock (stock_id))g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data)gtk_toolbar_insert (p_toolbar GTK_TOOL_ITEM (p_tool_item) -1)

XIII-C - Code source

chapitre13zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 38 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIV - Les racourcis clavier

XIV-A - Aperccedilu

Cliquez pour agrandir

XIV-B - Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mneacutemoniques ces derniers permettent dacceacuteder agrave un eacuteleacutementseacutequentiellement alors que les raccourcis appellent une fonction si lutilisateur appuie simultaneacutement sur une ouplusieurs touches (geacuteneacuteralement de la forme ltModificateurgtTouche ougrave Modificateur repreacutesente les touches ShiftAlt et Control) Ce raccourci peut ecirctre attacheacute agrave un eacuteleacutement du menu mais ceci nest pas obligatoire

Les raccourcis sont regroupeacutes en groupe dans un GtkAccelGroup quil faut commencer par creacuteer

raccourciscinclude ltgtkgtkhgtinclude callbackhinclude raccourcish

GtkAccelGroup accel_group_new (gpointer user_data) GtkAccelGroup p_accel_group = NULL

p_accel_group = gtk_accel_group_new () return p_accel_group

Vous commencez agrave avoir lhabitude de cette organisation nous allons donc creacuteer une fonction qui va se chargerdajouter un raccourci au groupe

raccourciscstatic void accelerator_new (GtkAccelGroup p_accel_group const gchar accelerator const gchar accel_path GCallback callback gpointer user_data) guint key GdkModifierType mods GClosure closure = NULL

gtk_accelerator_parse (accelerator ampkey ampmods) closure = g_cclosure_new (callback user_data NULL) gtk_accel_group_connect (p_accel_group key mods GTK_ACCEL_VISIBLE closure) gtk_accel_map_add_entry (accel_path key mods)

La fonction gtk_accelerator_parse permet de deacutecomposer une chaicircne de caractegraveres de la forme ltControlgtF1 ouencore ltAltgtA en numeacutero de touche et modificateur

En plus des touches pour creacuteer un raccourci clavier nous avons besoin dune fonction agrave appeler lorsque lutilisateurappuie sur les touches speacutecifieacutees gtk_accel_group_connect attend une fonction du type GClosure regardons ladocumentation de gobject pour savoir agrave quoi cela correspond

typedef struct

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 21 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GTK_RESPONSE_NO = -9 GTK_RESPONSE_APPLY = -10 GTK_RESPONSE_HELP = -11 GtkResponseType

Nous indiquons la fin des couples stock idreacuteponse id avec la valeur NULL

Une fois la boicircte de dialogue creacuteee on demande agrave GTK+ de lafficher gracircce agrave la fonction gtk_dialog_run puis onreacutecupegravere sa valeur de retour qui correspond au bouton cliqueacute par lutilisateur

callbackc if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

Ici ce qui nous inteacuteresse cest lorsque que lutilisateur clique sur le bouton ouvrir (donc gtk_dialog_run renvoieGTK_RESPONSE_ACCEPT) dans ce cas il nous suffit de reacutecupeacuterer le nom du fichier seacutelectionneacute puis de louvrir

callbackc gchar file_name = NULL

file_name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) open_file (file_name GTK_TEXT_VIEW (user_data)) g_free (file_name) file_name = NULL

Pour finir dans tous les cas on noublie pas de deacutetruire la boicircte de dialogue

callbackc gtk_widget_destroy (p_dialog)

Et voilagrave le travail lutilisateur peut ouvrir le fichier quil souhaite

VI-C - Code source

chapitre6zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 22 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VII - Interlude

Avant daller plus loin dans lameacutelioration de linterface de notre eacutediteur il est neacutecessaire de modifier sonfonctionnement interne (ne vous inquieacutetez je nai pas dit chambouler) en effet souvenez-vous dans lintroduction jaieacutevoqueacute la possibiliteacutes douvrir plusieurs documents gracircce agrave un systegraveme donglets Pour cela il faut sauvegarder lesproprieacuteteacutes de chaque document ouvert Pris agrave temps ce genre de modification nest pas trop lourde mais si nousattendons cela risque de devenir un vrai casse tecircte

Pour cela nous allons utiliser une structure de donneacutee pour chaque document ouvert qui devra garder en meacutemoirele chemin complet du fichier (ou NULL si le document nest pas encore sauvegarder) sil agrave eacutetait modifier depuis laderniegravere sauvegarde et le GtkTextView qui sert agrave son affichage Voici donc la structure qui va nous servir

documenthtypedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

Sachant que nous serons ameneacute agrave stocker plusieurs occurrences de cette structure il serait bon de reacutefleacutechir degravesmaintenant agrave la structure de donneacutee agrave utiliser pour les stocker La premiegravere ideacutee qui vient agrave lesprit est un tableaualloueacute dynamiquement cependant lutilisateur peut souhaiter fermer un document qui se trouve au milieu on estalors obligeacute de deacutecaler toutes les cellules en amont Dans ce cas il parait naturel dutiliser une liste chaicircneacutee Parchance la glib propose une bibliothegraveque de gestion des listes chaicircneacutees cela nous fera gagner du temps le momentvenu Pour linstant on se contente de creacuteer une structure de donneacutees qui contiendra tous les documents ouverts(stockeacutee dans une GList) et un pointeur sur le document actif (actuellement comme nous navons quun documentouvert en mecircme temps on manipulera uniquement ce pointeur)

documenthtypedef struct GList tous document_t actif docs_t

Maintenant se pose le problegraveme de savoir comment transmettre cette structure On pourrait se servir du paramegravetreuser_data preacutesent dans toutes les fonctions callback mais certaines fonctions utilise deacutejagrave ce paramegravetre (la fonctioncb_open par exemple) il faudrait creacuteer un champs suppleacutementaire dans notre structure documents_s Une solutionplus simple est de creacuteer une variable globale agrave lensemble du programme Ceux qui passe reacuteguliegraverement sur le forumC savent que cest fortement deacuteconseilleacute mais ici nous nous trouvons dans lune des rares exceptions agrave la regravegle Detoute faccedilon cela revient au mecircme que de passer ladresse de notre structure agrave toutes les fonctions callback Nousdeacutefinissons donc un nouveau fichier den-tecircte

documenthifndef H_DOCUMENTdefine H_DOCUMENT

include ltgtkgtkhgt

typedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 23 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

documenthtypedef struct GList tous document_t actif docs_t

extern docs_t docs

endif not H_DOCUMENT

Et dans le fichier mainc

maincinclude documenth

docs_t docs = NULL NULL

Pour linstant la seule fonction qui modifie leacutetat dun document est la fonction open_file il faut donc inclure documenthdans callbackc et modifier leacutegegraverement la fonction pour enregistrer le document ouvert

callbackc if (g_file_get_contents (file_name ampcontents NULL NULL)) Pour linstant il faut allouer la memoire par la suite on modifira simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = g_strdup (file_name) Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = p_text_view Le document vient detre ouvert il nest donc pas modifie docsactif-gtsauve = TRUE

Ne soyez pas choqueacute si je ne teste pas le retour de la fonction g_malloc pour veacuterifier quilnest pas NULL En effet cette derniegravere met fin agrave lapplication si lallocation eacutechoue

VII-A - Code source

chapitre7zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 24 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VIII - Sauvegarder les modification

VIII-A - Aperccedilu

Cliquez pour agrandir

VIII-B - Enregistrer

Avant de pouvoir sauvegarder un document il faut quil soit modifieacute Comment savoir que le contenu du fichier a eacuteteacutemodifier Gracircce au signal changed du GtkTextBuffer que nous interceptons gracircce agrave la fonction cb_modifie

mainc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (p_text_view)) g_signal_connect (G_OBJECT (p_text_buffer) changed G_CALLBACK (cb_modifie) NULL)

Cette derniegravere modifie simplement le champ sauve du document

callbackcvoid cb_modifie (GtkWidget p_widget gpointer user_data) if (docsactif) docsactif-gtsauve = FALSE

Pour la sauvegarde il faut distinguer deux cas soit il sagit de la premiegravere sauvegarde du fichier il faut alors demanderle nom du fichier agrave lutilisateur (cela ressemble fortement agrave louverture dun fichier) soit le fichier est deacutejagrave preacutesent surle disque il suffit de remplacer son contenu par celui du GtkTextViewer Nous avons convenu quun fichier qui neacutetaitpas encore enregistreacute avait sa proprieacuteteacute chemin agrave NULL

Bien sucircr cela na lieu que si un fichier est ouvert et quil a eacuteteacute modifieacute depuis sa derniegravere sauvegarde

callbackcvoid cb_save (GtkWidget p_widget gpointer user_data) if (docsactif) if (docsactif-gtsauve) Le fichier na pas encore ete enregistre if (docsactif-gtchemin) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Sauvegarder le fichier NULL GTK_FILE_CHOOSER_ACTION_SAVE GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_SAVE GTK_RESPONSE_ACCEPT NULL) if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 25 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc docsactif-gtchemin = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) gtk_widget_destroy (p_dialog) Soit le fichier a deja ete enregistre soit lutilisateur vient de nous fournir son nouvel enplacement on peut donc lenregistrer if (docsactif-gtchemin) else print_warning (Aucun document ouvert)

Il nous reste plus quagrave reacutecupeacuterer le contenu du GtkTextViewer et le copier dans le fichier chemin sans oublier dereconvertir le texte dans le codage local

callbackc FILE fichier = NULL

fichier = fopen (docsactif-gtchemin w) if (fichier) gchar contents = NULL gchar locale = NULL GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) contents = gtk_text_buffer_get_text (p_text_buffer ampstart ampend FALSE) locale = g_locale_from_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL fprintf (fichier s locale) g_free (locale) locale = NULL fclose (fichier) fichier = NULL docsactif-gtsauve = TRUE else print_warning (Impossible de sauvegarder le fichier s docsactif-gtchemin)

Le dernier paramegravetre de la fonction gtk_text_buffer_get_text est mis agrave FALSE car nous ne voulons pas enregistrerles caractegraveres invisibles preacutesent dans le GtkTextBuffer Ces caractegraveres servent agrave mettre en forme le texte (taillecouleur) nous pourrions creacuteer un nouveau format de fichier pour enregistrer la mise en forme

VIII-C - Enregistrer sous

Pour enregistrer notre document sous un autre nom il suffit de faire croire agrave cb_save que le document na pas encoreeacutetait enregistreacute tout simplement en changeant chemin agrave NULL et sauve agrave FALSE

callbackcvoid cb_saveas (GtkWidget p_widget gpointer user_data)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 26 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (docsactif) document_t tmp = docsactif

docsactif-gtchemin = NULL docsactif-gtsauve = FALSE cb_save (p_widget user_data) if (docsactif-gtsauve) (docsactif) = tmp else print_warning (Aucun document ouvert)

Il ne faut pas oublier que lutilisateur peut annuler lenregistrement de ce fait nous sauvegardons leacutetat du documentet si la sauvegarde na pas eu lieu on le restaure

VIII-D - Code source

chapitre8zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 27 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IX - Creacuteer un nouveau document

IX-A - Aperccedilu

Cliquez pour agrandir

IX-B - Nouveau fichier

Maintenant que lutilisateur peut ouvrir et fermer un fichier il est inteacuteressant de lui donner la possibiliteacute den creacuteerun nouveau Je ne reviens pas sur la creacuteation du bouton (ccedila devrait deacutejagrave ecirctre fait D) passons directement agrave lafonction cb_new

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) Pour linstant il faut allouer la memoire par la suite on modifiera simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = NULL Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = GTK_TEXT_VIEW (user_data) Le document vient detre creer il nest donc pas modifie docsactif-gtsauve = TRUE gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Je ne sais pas vous mais pour ma part jai fait un copiercoller de la fonction open_file Et oui ouvrir un document peutse reacutesumer agrave creacuteer un document vide puis remplir le GtkTextView avec le fichier souhaiteacute On peut donc simplifiernotre fonction open_file ainsi

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

cb_new (NULL p_text_view) gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE) p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1) Nous sommes obliges de remetre sauve a TRUE car linsertion du contenu du fichier dans le GtkTextView a appele cb_modfie docsactif-gtsauve = TRUE else print_warning (Impossible douvrir le fichier sn file_name)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 28 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc

Cest beau la factorisation du code Par contre nous sommes obligeacutes de remettre sauve agrave TRUE car nous avonsmodifieacute le GtkTextBuffer

IX-C - Code source

chapitre9zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 29 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

X - Fermer

X-A - Aperccedilu

Cliquez pour agrandir

X-B - Fermer un fichier

Maintenant que nous allouons de la meacutemoire il faut la libeacuterer agrave un endroit Logiquement cela va ecirctre fait agrave la fermeturedu document en guise dexercice je vous laisse creacuteer le bouton dans notre boicircte agrave bouton

Allez je vous aide le stock id correspondant est GTK_STOCK_CLOSE

Voilagrave maintenant si tout cest bien passeacute vous devriez ecirctre arriveacute dans le fichier callbackc avec quelque choseressemblant agrave

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data)

Lorsque lon ferme un document il faut vider le GtkTextView (avec les onglets on se contentera de le supprimer)pour cela il faut reacutecupeacuterer le deacutebut et la fin du GtkTextBuffer et demander agrave GTK+ de supprimer tout ce qui ce trouveentre les deux iteacuterateurs

callbackc Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) gtk_text_buffer_delete (p_text_buffer ampstart ampend) else print_warning (Aucun document ouvert)

Bien sucircr il ne faut pas oublier de libeacuterer la meacutemoire

callbackc g_free (docsactif-gtchemin) docsactif-gtchemin = NULL docsactif-gtp_text_view = NULL g_free (docsactif) docsactif = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 30 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour symboliser la fermeture dun document nous deacutesactivons le GtkTextView lors de la fermeture (ne pas oublierde le faire aussi dans mainc)

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) FALSE)

Et nous le reacuteactivons lors de louverture si celle si reacuteussie

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Lorsque lutilisateur quitte lapplication il faut bien sucircr fermer le document sil y en a un ouvert

void cb_quit (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data) gtk_main_quit()

Et aussi lorsquil creacuteeacute un nouveau document (et par conseacutequent lorsquil ouvre un fichier puisque lon fait appel agravecb_new)

void cb_new (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data)

X-C - Enregistrer avant de fermer

Si le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde geacuteneacuteralement le programme le signale agrave lutilisateur etlui propose de sauvegarder ou dannuler la fermeture Pour se faire nous devons modifier la fonction cb_close avantde fermer le document nous allons afficher une boicircte de dialogue

Pour creacuteer une boicircte de dialogue simplement il existe la classe GtkDialog et comme nous avons besoin de boutons(pour que lutilisateur fasse son choix) nous allons creacuteer notre boicircte avec la fonction

GtkWidget gtk_dialog_new_with_buttons (const gchar title GtkWindow parent GtkDialogFlags flags const gchar first_button_text )

Nous retrouvons les mecircmes options que pour le GtkFileChooserDialog mis agrave part option du type GtkDialogFlags

typedef enum GTK_DIALOG_MODAL = 1 ltlt 0 appel gtk_window_set_modal (win TRUE) GTK_DIALOG_DESTROY_WITH_PARENT = 1 ltlt 1 appel gtk_window_set_destroy_with_parent () GTK_DIALOG_NO_SEPARATOR = 1 ltlt 2 Pas de barre de separation au dessus des boutons GtkDialogFlags

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 31 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Nous nous contenterons de rendre notre fenecirctre modale (7)

Pour avoir accegraves agrave notre fenecirctre principale nous ajoutons un champs p_main_window agrave notre structure globaledocs_t que nous initialisons dans la fonction main

mainc docsp_main_window = GTK_WINDOW (p_window)

Il nous reste plus qua creacuteer notre boicircte de dialogue avec trois boutons Oui Non Annuler

callbackc if (docsactif-gtsauve) GtkWidget p_dialog = NULL

p_dialog = gtk_dialog_new_with_buttons (Sauvegarder docsp_main_window GTK_DIALOG_MODAL GTK_STOCK_YES GTK_RESPONSE_YES GTK_STOCK_NO GTK_RESPONSE_NO GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL NULL)

Nous obtenons donc une structure de type GtkDialog

typedef struct GtkWidget vbox GtkWidget action_area GtkDialog

Nous remarquons que cette structure contient deux membres qui permettent dacceacuteder agrave une GtkBox ougrave nous allonsajouter le contenu de la fenecirctre et agrave la partie contenant les boutons

Ensuite la construction de la fenecirctre est identique agrave celle de la fenecirctre principale ici nous nous contenterons dajouterun GtkLabel

callbackc GtkWidget p_label = NULL p_label = gtk_label_new (Voulez-vous sauvegarder les modifications ) gtk_box_pack_start (GTK_BOX (GTK_DIALOG (p_dialog)-gtvbox) p_label TRUE TRUE 0)

Une fois notre fenecirctre precircte il suffit de faire appel agrave la fonction gtk_dialog_run qui va afficher notre GtkDialog et nousretourner le reacuteponse id correspondant au bouton cliqueacute par lutilisateur

callbackc switch (gtk_dialog_run (GTK_DIALOG (p_dialog))) case GTK_RESPONSE_YES cb_save (p_widget user_data) break case GTK_RESPONSE_NO break case GTK_RESPONSE_CANCEL gtk_widget_destroy (p_dialog) return break

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 32 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc gtk_widget_destroy (p_dialog)

Si lutilisateur clique sur non on ne fait rien (le document sera simplement fermeacute) sur oui on enregistre avant defermer et pour finir sil annule on quitte la fonction

X-D - Code source

chapitre10zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 33 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XI - Les barres de deacutefilement

XI-A - Aperccedilu

Cliquez pour agrandir

XI-B - Ajouter des barres de deacutefilement

Apregraves le dernier chapitre quelque peu laborieux voici une partie plus simple mais qui va rendre notre applicationplus pratique En effet si vous avez essayeacute douvrir un fichier de grande taille vous avez pu remarquer que pourpouvoir lire la fin du fichier il fallait utiliser les touches du clavier pas tregraves convivial

Pour rendre la navigation plus aiseacutee on utilise des barres de deacutefilement

mainc GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_scrolled_window TRUE TRUE 0)

Creation de la zone de texte gtk_container_add (GTK_CONTAINER (p_scrolled_window) p_text_view)

Le constructeur de notre GtkScrolledWindow prend en argument deux GtkAdjustment qui permettent de deacutefinirdiffeacuterentes proprieacuteteacutes de la barre de deacutefilement (taille dune page la position de deacutepart) nous laissons GTK+ faireen passant NULL

Cest un bon deacutebut mais estheacutetiquement on peut faire mieux mecircme sil nest pas utile davoir une barre de deacutefilementelle est quand mecircme afficheacutee On peut demander agrave GTK+ de les afficher que si cela est neacutecessaire

mainc gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC)

En fait nous avons de la chance car la classe GtkTextView fait partie des widget qui supporte de faccedilon native les barresde deacutefilement Comment le savoir Ce genre de widget possegravede une ou deux proprieacuteteacutes de type GtkAdjustment (unepour la barre verticale lautre pour la barre horizontale) Actuellement seulement trois classes en sont capables lesGtkTextView les GtkTreeView et les GtkLayout

Comment faire pour les autres widgets Il faut passer par une classe adaptateur GtkViewport afin de creacuteer lesGtkAdjustment

XI-C - Code source

chapitre11zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 34 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XII - Les menus

XII-A - Aperccedilu

Cliquez pour agrandir

XII-B - Creacuteation du menu

Pour simplifier nous avons utiliseacute des boutons pour permettre agrave lutilisateur de creacuteer un document ouvrir un fichierMais il est plus courant dutiliser un menu pour afficher ces options GTK+ propose trois maniegraveres de creacuteer un menu

bull GtkItemFactory cette meacutethode est obsolegravete depuis la version 24 de GTK+

bull GtkUIManager cest ce quon appel une usine agrave gaz pour en savoir plus vous pouvez vous reporter aututoriel Utilisation de GtkUIManager

bull GtkMenu cest ce widget que nous allons eacutetudier il permet de creacuteer un menu manuellement (agrave lopposeacute deGtkUIManager)

Un menu selon GTK+ est composeacute de plusieurs eacuteleacutements

bull GtkMenuBar la barre de menu elle-mecircme

bull GtkMenu la partie deacuteroulante qui contient les diffeacuterents eacuteleacutements

bull GtkMenuItem cest sur ce widget que lutilisateur clique pour lancer une action

Pour commencer faisons linventaire de ce que nous avons besoin

bull Un GtkMenuBar qui sert de base au menu

bull Un GtkMenu pour commencer nous nous aurons dun menu Fichier

bull Six GtkMenuItem pour remplacer nos six boutons

Commenccedilons par la creacuteation du menu nous mettons ce code dans un nouveau fichier dont seul la fonction menu_newsera accessible

menucGtkMenuBar menu_new (gpointer user_data) GtkWidget p_menu_bar = NULL

p_menu_bar = gtk_menu_bar_new () return GTK_MENU_BAR (p_menu_bar)

Le paramegravetre user_data nous servira lors de la connexion des callbacks (nous en avons besoin pour les fonctionscb_new et cb_open)

Ensuite nous allons creacuteer notre sous menu Fichier

menuc Menu Fichier

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 35 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

menuc GtkWidget p_menu = NULL GtkWidget p_menu_item = NULL

p_menu = gtk_menu_new () p_menu_item = gtk_menu_item_new_with_mnemonic (_Fichier) gtk_menu_item_set_submenu (GTK_MENU_ITEM (p_menu_item) p_menu) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu_bar) p_menu_item) return GTK_MENU_BAR (p_menu_bar)

Un sous menu est en fait un GtkMenuItem auquel on assigne un GtkMenu Il faut bien sucircr terminer la creacuteation dusous-menu en lajoutant agrave la barre de menu

Pour finir nous creacuteons les eacuteleacutements du menu les GtkItemMenu Il existe plusieurs types deacuteleacutements (comparableaux diffeacuterents types de bouton) pour commencer nous nutiliserons que le type de base Comme cette opeacuteration estreacutepeacutetitive nous allons creacuteer une fonction pour le faire

menucstatic void menu_item_new (GtkMenu p_menu const gchar title GCallback callback gpointer user_data) GtkWidget p_menu_item = NULL

p_menu_item = gtk_menu_item_new_with_mnemonic (title) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu) p_menu_item) g_signal_connect (G_OBJECT (p_menu_item) activate callback user_data)

Pour permettre agrave lutilisateur dacceacuteder aux diffeacuterents eacuteleacutements du menu agrave laide de la touche ltAltgt nous utilisonsdes mneacutemoniques par exemple pour quitter leacutediteur il suffit de faite Alt+F puis Q Et voici le code pour creacuteer nossix eacuteleacutements du menu

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau G_CALLBACK (cb_new) user_data) menu_item_new (GTK_MENU (p_menu) _Ouvrir G_CALLBACK (cb_open) user_data) menu_item_new (GTK_MENU (p_menu) _Enregistrer G_CALLBACK (cb_save) user_data) menu_item_new (GTK_MENU (p_menu) Enregistrer _sous G_CALLBACK (cb_saveas) user_data) menu_item_new (GTK_MENU (p_menu) _Fermer G_CALLBACK (cb_close) user_data) menu_item_new (GTK_MENU (p_menu) _Quitter G_CALLBACK (cb_quit) user_data)

Voilagrave notre menu est creacuteeacute il nous reste plus quagrave linteacutegrer agrave notre fenecirctre

mainc gtk_box_pack_start (GTK_BOX (p_main_box) GTK_WIDGET (menu_new (p_text_view)) FALSE FALSE 0)

Le problegraveme cest que nous avons besoin de passer le GtkTextView lors de la creacuteation du menu (qui est utiliseacute par lesfonctions cb_new et cb_open) or celui-ci est creacuteeacute apregraves le menu (puisque nous creacuteons les widgets dans lordre ougrave ilfaut les inteacutegrer agrave linterface (8) ) nous devons creacuteer le GtkTextView (seul lappel agrave gtk_text_view_new est deacuteplaceacute)

XII-C - Code source

chapitre12zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 36 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIII - Les barres doutils

XIII-A - Aperccedilu

Cliquez pour agrandir

XIII-B - Creacuteation dune barre doutils

La creacuteation dune barre doutils ressemble fort agrave celle dun menu en plus simple puisquil ny a pas de sous menu on creacutee notre barre doutils (gtk_toolbar_new) puis les eacuteleacutements de la barre pour cela on utilise des boutons(gtk_tool_button_new_from_stock) que lon inseacutere dans la barre (gtk_toolbar_insert) Pas conseacutequent notre fichierbarreoutilsc ressemble agrave menuc

barreoutilscinclude ltgtkgtkhgtinclude callbackhinclude barreoutilsh

static void toolbar_item_new (GtkToolbar const gchar GCallback gpointer)

GtkToolbar toolbar_new (gpointer user_data) GtkWidget p_toolbar = NULL

p_toolbar = gtk_toolbar_new () toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_NEW G_CALLBACK (cb_new) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_OPEN G_CALLBACK (cb_open) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE G_CALLBACK (cb_save) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE_AS G_CALLBACK (cb_saveas) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_CLOSE G_CALLBACK (cb_close) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_QUIT G_CALLBACK (cb_quit) user_data) return GTK_TOOLBAR (p_toolbar)

static void toolbar_item_new (GtkToolbar p_toolbar const gchar stock_id GCallback callback gpointer user_data) GtkToolItem p_tool_item = NULL

p_tool_item = gtk_tool_button_new_from_stock (stock_id) g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data) gtk_toolbar_insert (p_toolbar p_tool_item -1)

Le code nest pas complet car lorsque jexeacutecute le programme GTK+ affiche en plus des icocircnes le texte sous lesboutons Pour modifier cela il suffit dajouter une ligne de code

barreoutilsc gtk_toolbar_set_style (GTK_TOOLBAR (p_toolbar) GTK_TOOLBAR_ICONS)

Pourquoi gtk_tool_button_new_from_stock retourne un GtkToolItem et non un GtkWidgetcomme nous avons eacuteteacute habitueacute jusquagrave preacutesent Il sagit dune bizarrerie de GTK+ dontje ne connais pas la raison

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 37 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour anticiper un changement dinterface (dans GTK+ 30 peut ecirctre ) nous aurions pueacutecrire

Gtkwidget p_tool_item = NULL

p_tool_item = GTK_WIDGET (gtk_tool_button_new_from_stock (stock_id))g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data)gtk_toolbar_insert (p_toolbar GTK_TOOL_ITEM (p_tool_item) -1)

XIII-C - Code source

chapitre13zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 38 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIV - Les racourcis clavier

XIV-A - Aperccedilu

Cliquez pour agrandir

XIV-B - Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mneacutemoniques ces derniers permettent dacceacuteder agrave un eacuteleacutementseacutequentiellement alors que les raccourcis appellent une fonction si lutilisateur appuie simultaneacutement sur une ouplusieurs touches (geacuteneacuteralement de la forme ltModificateurgtTouche ougrave Modificateur repreacutesente les touches ShiftAlt et Control) Ce raccourci peut ecirctre attacheacute agrave un eacuteleacutement du menu mais ceci nest pas obligatoire

Les raccourcis sont regroupeacutes en groupe dans un GtkAccelGroup quil faut commencer par creacuteer

raccourciscinclude ltgtkgtkhgtinclude callbackhinclude raccourcish

GtkAccelGroup accel_group_new (gpointer user_data) GtkAccelGroup p_accel_group = NULL

p_accel_group = gtk_accel_group_new () return p_accel_group

Vous commencez agrave avoir lhabitude de cette organisation nous allons donc creacuteer une fonction qui va se chargerdajouter un raccourci au groupe

raccourciscstatic void accelerator_new (GtkAccelGroup p_accel_group const gchar accelerator const gchar accel_path GCallback callback gpointer user_data) guint key GdkModifierType mods GClosure closure = NULL

gtk_accelerator_parse (accelerator ampkey ampmods) closure = g_cclosure_new (callback user_data NULL) gtk_accel_group_connect (p_accel_group key mods GTK_ACCEL_VISIBLE closure) gtk_accel_map_add_entry (accel_path key mods)

La fonction gtk_accelerator_parse permet de deacutecomposer une chaicircne de caractegraveres de la forme ltControlgtF1 ouencore ltAltgtA en numeacutero de touche et modificateur

En plus des touches pour creacuteer un raccourci clavier nous avons besoin dune fonction agrave appeler lorsque lutilisateurappuie sur les touches speacutecifieacutees gtk_accel_group_connect attend une fonction du type GClosure regardons ladocumentation de gobject pour savoir agrave quoi cela correspond

typedef struct

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 22 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VII - Interlude

Avant daller plus loin dans lameacutelioration de linterface de notre eacutediteur il est neacutecessaire de modifier sonfonctionnement interne (ne vous inquieacutetez je nai pas dit chambouler) en effet souvenez-vous dans lintroduction jaieacutevoqueacute la possibiliteacutes douvrir plusieurs documents gracircce agrave un systegraveme donglets Pour cela il faut sauvegarder lesproprieacuteteacutes de chaque document ouvert Pris agrave temps ce genre de modification nest pas trop lourde mais si nousattendons cela risque de devenir un vrai casse tecircte

Pour cela nous allons utiliser une structure de donneacutee pour chaque document ouvert qui devra garder en meacutemoirele chemin complet du fichier (ou NULL si le document nest pas encore sauvegarder) sil agrave eacutetait modifier depuis laderniegravere sauvegarde et le GtkTextView qui sert agrave son affichage Voici donc la structure qui va nous servir

documenthtypedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

Sachant que nous serons ameneacute agrave stocker plusieurs occurrences de cette structure il serait bon de reacutefleacutechir degravesmaintenant agrave la structure de donneacutee agrave utiliser pour les stocker La premiegravere ideacutee qui vient agrave lesprit est un tableaualloueacute dynamiquement cependant lutilisateur peut souhaiter fermer un document qui se trouve au milieu on estalors obligeacute de deacutecaler toutes les cellules en amont Dans ce cas il parait naturel dutiliser une liste chaicircneacutee Parchance la glib propose une bibliothegraveque de gestion des listes chaicircneacutees cela nous fera gagner du temps le momentvenu Pour linstant on se contente de creacuteer une structure de donneacutees qui contiendra tous les documents ouverts(stockeacutee dans une GList) et un pointeur sur le document actif (actuellement comme nous navons quun documentouvert en mecircme temps on manipulera uniquement ce pointeur)

documenthtypedef struct GList tous document_t actif docs_t

Maintenant se pose le problegraveme de savoir comment transmettre cette structure On pourrait se servir du paramegravetreuser_data preacutesent dans toutes les fonctions callback mais certaines fonctions utilise deacutejagrave ce paramegravetre (la fonctioncb_open par exemple) il faudrait creacuteer un champs suppleacutementaire dans notre structure documents_s Une solutionplus simple est de creacuteer une variable globale agrave lensemble du programme Ceux qui passe reacuteguliegraverement sur le forumC savent que cest fortement deacuteconseilleacute mais ici nous nous trouvons dans lune des rares exceptions agrave la regravegle Detoute faccedilon cela revient au mecircme que de passer ladresse de notre structure agrave toutes les fonctions callback Nousdeacutefinissons donc un nouveau fichier den-tecircte

documenthifndef H_DOCUMENTdefine H_DOCUMENT

include ltgtkgtkhgt

typedef struct gchar chemin gboolean sauve GtkTextView p_text_view document_t

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 23 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

documenthtypedef struct GList tous document_t actif docs_t

extern docs_t docs

endif not H_DOCUMENT

Et dans le fichier mainc

maincinclude documenth

docs_t docs = NULL NULL

Pour linstant la seule fonction qui modifie leacutetat dun document est la fonction open_file il faut donc inclure documenthdans callbackc et modifier leacutegegraverement la fonction pour enregistrer le document ouvert

callbackc if (g_file_get_contents (file_name ampcontents NULL NULL)) Pour linstant il faut allouer la memoire par la suite on modifira simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = g_strdup (file_name) Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = p_text_view Le document vient detre ouvert il nest donc pas modifie docsactif-gtsauve = TRUE

Ne soyez pas choqueacute si je ne teste pas le retour de la fonction g_malloc pour veacuterifier quilnest pas NULL En effet cette derniegravere met fin agrave lapplication si lallocation eacutechoue

VII-A - Code source

chapitre7zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 24 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VIII - Sauvegarder les modification

VIII-A - Aperccedilu

Cliquez pour agrandir

VIII-B - Enregistrer

Avant de pouvoir sauvegarder un document il faut quil soit modifieacute Comment savoir que le contenu du fichier a eacuteteacutemodifier Gracircce au signal changed du GtkTextBuffer que nous interceptons gracircce agrave la fonction cb_modifie

mainc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (p_text_view)) g_signal_connect (G_OBJECT (p_text_buffer) changed G_CALLBACK (cb_modifie) NULL)

Cette derniegravere modifie simplement le champ sauve du document

callbackcvoid cb_modifie (GtkWidget p_widget gpointer user_data) if (docsactif) docsactif-gtsauve = FALSE

Pour la sauvegarde il faut distinguer deux cas soit il sagit de la premiegravere sauvegarde du fichier il faut alors demanderle nom du fichier agrave lutilisateur (cela ressemble fortement agrave louverture dun fichier) soit le fichier est deacutejagrave preacutesent surle disque il suffit de remplacer son contenu par celui du GtkTextViewer Nous avons convenu quun fichier qui neacutetaitpas encore enregistreacute avait sa proprieacuteteacute chemin agrave NULL

Bien sucircr cela na lieu que si un fichier est ouvert et quil a eacuteteacute modifieacute depuis sa derniegravere sauvegarde

callbackcvoid cb_save (GtkWidget p_widget gpointer user_data) if (docsactif) if (docsactif-gtsauve) Le fichier na pas encore ete enregistre if (docsactif-gtchemin) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Sauvegarder le fichier NULL GTK_FILE_CHOOSER_ACTION_SAVE GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_SAVE GTK_RESPONSE_ACCEPT NULL) if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 25 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc docsactif-gtchemin = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) gtk_widget_destroy (p_dialog) Soit le fichier a deja ete enregistre soit lutilisateur vient de nous fournir son nouvel enplacement on peut donc lenregistrer if (docsactif-gtchemin) else print_warning (Aucun document ouvert)

Il nous reste plus quagrave reacutecupeacuterer le contenu du GtkTextViewer et le copier dans le fichier chemin sans oublier dereconvertir le texte dans le codage local

callbackc FILE fichier = NULL

fichier = fopen (docsactif-gtchemin w) if (fichier) gchar contents = NULL gchar locale = NULL GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) contents = gtk_text_buffer_get_text (p_text_buffer ampstart ampend FALSE) locale = g_locale_from_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL fprintf (fichier s locale) g_free (locale) locale = NULL fclose (fichier) fichier = NULL docsactif-gtsauve = TRUE else print_warning (Impossible de sauvegarder le fichier s docsactif-gtchemin)

Le dernier paramegravetre de la fonction gtk_text_buffer_get_text est mis agrave FALSE car nous ne voulons pas enregistrerles caractegraveres invisibles preacutesent dans le GtkTextBuffer Ces caractegraveres servent agrave mettre en forme le texte (taillecouleur) nous pourrions creacuteer un nouveau format de fichier pour enregistrer la mise en forme

VIII-C - Enregistrer sous

Pour enregistrer notre document sous un autre nom il suffit de faire croire agrave cb_save que le document na pas encoreeacutetait enregistreacute tout simplement en changeant chemin agrave NULL et sauve agrave FALSE

callbackcvoid cb_saveas (GtkWidget p_widget gpointer user_data)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 26 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (docsactif) document_t tmp = docsactif

docsactif-gtchemin = NULL docsactif-gtsauve = FALSE cb_save (p_widget user_data) if (docsactif-gtsauve) (docsactif) = tmp else print_warning (Aucun document ouvert)

Il ne faut pas oublier que lutilisateur peut annuler lenregistrement de ce fait nous sauvegardons leacutetat du documentet si la sauvegarde na pas eu lieu on le restaure

VIII-D - Code source

chapitre8zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 27 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IX - Creacuteer un nouveau document

IX-A - Aperccedilu

Cliquez pour agrandir

IX-B - Nouveau fichier

Maintenant que lutilisateur peut ouvrir et fermer un fichier il est inteacuteressant de lui donner la possibiliteacute den creacuteerun nouveau Je ne reviens pas sur la creacuteation du bouton (ccedila devrait deacutejagrave ecirctre fait D) passons directement agrave lafonction cb_new

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) Pour linstant il faut allouer la memoire par la suite on modifiera simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = NULL Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = GTK_TEXT_VIEW (user_data) Le document vient detre creer il nest donc pas modifie docsactif-gtsauve = TRUE gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Je ne sais pas vous mais pour ma part jai fait un copiercoller de la fonction open_file Et oui ouvrir un document peutse reacutesumer agrave creacuteer un document vide puis remplir le GtkTextView avec le fichier souhaiteacute On peut donc simplifiernotre fonction open_file ainsi

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

cb_new (NULL p_text_view) gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE) p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1) Nous sommes obliges de remetre sauve a TRUE car linsertion du contenu du fichier dans le GtkTextView a appele cb_modfie docsactif-gtsauve = TRUE else print_warning (Impossible douvrir le fichier sn file_name)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 28 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc

Cest beau la factorisation du code Par contre nous sommes obligeacutes de remettre sauve agrave TRUE car nous avonsmodifieacute le GtkTextBuffer

IX-C - Code source

chapitre9zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 29 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

X - Fermer

X-A - Aperccedilu

Cliquez pour agrandir

X-B - Fermer un fichier

Maintenant que nous allouons de la meacutemoire il faut la libeacuterer agrave un endroit Logiquement cela va ecirctre fait agrave la fermeturedu document en guise dexercice je vous laisse creacuteer le bouton dans notre boicircte agrave bouton

Allez je vous aide le stock id correspondant est GTK_STOCK_CLOSE

Voilagrave maintenant si tout cest bien passeacute vous devriez ecirctre arriveacute dans le fichier callbackc avec quelque choseressemblant agrave

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data)

Lorsque lon ferme un document il faut vider le GtkTextView (avec les onglets on se contentera de le supprimer)pour cela il faut reacutecupeacuterer le deacutebut et la fin du GtkTextBuffer et demander agrave GTK+ de supprimer tout ce qui ce trouveentre les deux iteacuterateurs

callbackc Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) gtk_text_buffer_delete (p_text_buffer ampstart ampend) else print_warning (Aucun document ouvert)

Bien sucircr il ne faut pas oublier de libeacuterer la meacutemoire

callbackc g_free (docsactif-gtchemin) docsactif-gtchemin = NULL docsactif-gtp_text_view = NULL g_free (docsactif) docsactif = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 30 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour symboliser la fermeture dun document nous deacutesactivons le GtkTextView lors de la fermeture (ne pas oublierde le faire aussi dans mainc)

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) FALSE)

Et nous le reacuteactivons lors de louverture si celle si reacuteussie

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Lorsque lutilisateur quitte lapplication il faut bien sucircr fermer le document sil y en a un ouvert

void cb_quit (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data) gtk_main_quit()

Et aussi lorsquil creacuteeacute un nouveau document (et par conseacutequent lorsquil ouvre un fichier puisque lon fait appel agravecb_new)

void cb_new (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data)

X-C - Enregistrer avant de fermer

Si le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde geacuteneacuteralement le programme le signale agrave lutilisateur etlui propose de sauvegarder ou dannuler la fermeture Pour se faire nous devons modifier la fonction cb_close avantde fermer le document nous allons afficher une boicircte de dialogue

Pour creacuteer une boicircte de dialogue simplement il existe la classe GtkDialog et comme nous avons besoin de boutons(pour que lutilisateur fasse son choix) nous allons creacuteer notre boicircte avec la fonction

GtkWidget gtk_dialog_new_with_buttons (const gchar title GtkWindow parent GtkDialogFlags flags const gchar first_button_text )

Nous retrouvons les mecircmes options que pour le GtkFileChooserDialog mis agrave part option du type GtkDialogFlags

typedef enum GTK_DIALOG_MODAL = 1 ltlt 0 appel gtk_window_set_modal (win TRUE) GTK_DIALOG_DESTROY_WITH_PARENT = 1 ltlt 1 appel gtk_window_set_destroy_with_parent () GTK_DIALOG_NO_SEPARATOR = 1 ltlt 2 Pas de barre de separation au dessus des boutons GtkDialogFlags

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 31 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Nous nous contenterons de rendre notre fenecirctre modale (7)

Pour avoir accegraves agrave notre fenecirctre principale nous ajoutons un champs p_main_window agrave notre structure globaledocs_t que nous initialisons dans la fonction main

mainc docsp_main_window = GTK_WINDOW (p_window)

Il nous reste plus qua creacuteer notre boicircte de dialogue avec trois boutons Oui Non Annuler

callbackc if (docsactif-gtsauve) GtkWidget p_dialog = NULL

p_dialog = gtk_dialog_new_with_buttons (Sauvegarder docsp_main_window GTK_DIALOG_MODAL GTK_STOCK_YES GTK_RESPONSE_YES GTK_STOCK_NO GTK_RESPONSE_NO GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL NULL)

Nous obtenons donc une structure de type GtkDialog

typedef struct GtkWidget vbox GtkWidget action_area GtkDialog

Nous remarquons que cette structure contient deux membres qui permettent dacceacuteder agrave une GtkBox ougrave nous allonsajouter le contenu de la fenecirctre et agrave la partie contenant les boutons

Ensuite la construction de la fenecirctre est identique agrave celle de la fenecirctre principale ici nous nous contenterons dajouterun GtkLabel

callbackc GtkWidget p_label = NULL p_label = gtk_label_new (Voulez-vous sauvegarder les modifications ) gtk_box_pack_start (GTK_BOX (GTK_DIALOG (p_dialog)-gtvbox) p_label TRUE TRUE 0)

Une fois notre fenecirctre precircte il suffit de faire appel agrave la fonction gtk_dialog_run qui va afficher notre GtkDialog et nousretourner le reacuteponse id correspondant au bouton cliqueacute par lutilisateur

callbackc switch (gtk_dialog_run (GTK_DIALOG (p_dialog))) case GTK_RESPONSE_YES cb_save (p_widget user_data) break case GTK_RESPONSE_NO break case GTK_RESPONSE_CANCEL gtk_widget_destroy (p_dialog) return break

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 32 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc gtk_widget_destroy (p_dialog)

Si lutilisateur clique sur non on ne fait rien (le document sera simplement fermeacute) sur oui on enregistre avant defermer et pour finir sil annule on quitte la fonction

X-D - Code source

chapitre10zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 33 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XI - Les barres de deacutefilement

XI-A - Aperccedilu

Cliquez pour agrandir

XI-B - Ajouter des barres de deacutefilement

Apregraves le dernier chapitre quelque peu laborieux voici une partie plus simple mais qui va rendre notre applicationplus pratique En effet si vous avez essayeacute douvrir un fichier de grande taille vous avez pu remarquer que pourpouvoir lire la fin du fichier il fallait utiliser les touches du clavier pas tregraves convivial

Pour rendre la navigation plus aiseacutee on utilise des barres de deacutefilement

mainc GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_scrolled_window TRUE TRUE 0)

Creation de la zone de texte gtk_container_add (GTK_CONTAINER (p_scrolled_window) p_text_view)

Le constructeur de notre GtkScrolledWindow prend en argument deux GtkAdjustment qui permettent de deacutefinirdiffeacuterentes proprieacuteteacutes de la barre de deacutefilement (taille dune page la position de deacutepart) nous laissons GTK+ faireen passant NULL

Cest un bon deacutebut mais estheacutetiquement on peut faire mieux mecircme sil nest pas utile davoir une barre de deacutefilementelle est quand mecircme afficheacutee On peut demander agrave GTK+ de les afficher que si cela est neacutecessaire

mainc gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC)

En fait nous avons de la chance car la classe GtkTextView fait partie des widget qui supporte de faccedilon native les barresde deacutefilement Comment le savoir Ce genre de widget possegravede une ou deux proprieacuteteacutes de type GtkAdjustment (unepour la barre verticale lautre pour la barre horizontale) Actuellement seulement trois classes en sont capables lesGtkTextView les GtkTreeView et les GtkLayout

Comment faire pour les autres widgets Il faut passer par une classe adaptateur GtkViewport afin de creacuteer lesGtkAdjustment

XI-C - Code source

chapitre11zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 34 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XII - Les menus

XII-A - Aperccedilu

Cliquez pour agrandir

XII-B - Creacuteation du menu

Pour simplifier nous avons utiliseacute des boutons pour permettre agrave lutilisateur de creacuteer un document ouvrir un fichierMais il est plus courant dutiliser un menu pour afficher ces options GTK+ propose trois maniegraveres de creacuteer un menu

bull GtkItemFactory cette meacutethode est obsolegravete depuis la version 24 de GTK+

bull GtkUIManager cest ce quon appel une usine agrave gaz pour en savoir plus vous pouvez vous reporter aututoriel Utilisation de GtkUIManager

bull GtkMenu cest ce widget que nous allons eacutetudier il permet de creacuteer un menu manuellement (agrave lopposeacute deGtkUIManager)

Un menu selon GTK+ est composeacute de plusieurs eacuteleacutements

bull GtkMenuBar la barre de menu elle-mecircme

bull GtkMenu la partie deacuteroulante qui contient les diffeacuterents eacuteleacutements

bull GtkMenuItem cest sur ce widget que lutilisateur clique pour lancer une action

Pour commencer faisons linventaire de ce que nous avons besoin

bull Un GtkMenuBar qui sert de base au menu

bull Un GtkMenu pour commencer nous nous aurons dun menu Fichier

bull Six GtkMenuItem pour remplacer nos six boutons

Commenccedilons par la creacuteation du menu nous mettons ce code dans un nouveau fichier dont seul la fonction menu_newsera accessible

menucGtkMenuBar menu_new (gpointer user_data) GtkWidget p_menu_bar = NULL

p_menu_bar = gtk_menu_bar_new () return GTK_MENU_BAR (p_menu_bar)

Le paramegravetre user_data nous servira lors de la connexion des callbacks (nous en avons besoin pour les fonctionscb_new et cb_open)

Ensuite nous allons creacuteer notre sous menu Fichier

menuc Menu Fichier

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 35 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

menuc GtkWidget p_menu = NULL GtkWidget p_menu_item = NULL

p_menu = gtk_menu_new () p_menu_item = gtk_menu_item_new_with_mnemonic (_Fichier) gtk_menu_item_set_submenu (GTK_MENU_ITEM (p_menu_item) p_menu) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu_bar) p_menu_item) return GTK_MENU_BAR (p_menu_bar)

Un sous menu est en fait un GtkMenuItem auquel on assigne un GtkMenu Il faut bien sucircr terminer la creacuteation dusous-menu en lajoutant agrave la barre de menu

Pour finir nous creacuteons les eacuteleacutements du menu les GtkItemMenu Il existe plusieurs types deacuteleacutements (comparableaux diffeacuterents types de bouton) pour commencer nous nutiliserons que le type de base Comme cette opeacuteration estreacutepeacutetitive nous allons creacuteer une fonction pour le faire

menucstatic void menu_item_new (GtkMenu p_menu const gchar title GCallback callback gpointer user_data) GtkWidget p_menu_item = NULL

p_menu_item = gtk_menu_item_new_with_mnemonic (title) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu) p_menu_item) g_signal_connect (G_OBJECT (p_menu_item) activate callback user_data)

Pour permettre agrave lutilisateur dacceacuteder aux diffeacuterents eacuteleacutements du menu agrave laide de la touche ltAltgt nous utilisonsdes mneacutemoniques par exemple pour quitter leacutediteur il suffit de faite Alt+F puis Q Et voici le code pour creacuteer nossix eacuteleacutements du menu

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau G_CALLBACK (cb_new) user_data) menu_item_new (GTK_MENU (p_menu) _Ouvrir G_CALLBACK (cb_open) user_data) menu_item_new (GTK_MENU (p_menu) _Enregistrer G_CALLBACK (cb_save) user_data) menu_item_new (GTK_MENU (p_menu) Enregistrer _sous G_CALLBACK (cb_saveas) user_data) menu_item_new (GTK_MENU (p_menu) _Fermer G_CALLBACK (cb_close) user_data) menu_item_new (GTK_MENU (p_menu) _Quitter G_CALLBACK (cb_quit) user_data)

Voilagrave notre menu est creacuteeacute il nous reste plus quagrave linteacutegrer agrave notre fenecirctre

mainc gtk_box_pack_start (GTK_BOX (p_main_box) GTK_WIDGET (menu_new (p_text_view)) FALSE FALSE 0)

Le problegraveme cest que nous avons besoin de passer le GtkTextView lors de la creacuteation du menu (qui est utiliseacute par lesfonctions cb_new et cb_open) or celui-ci est creacuteeacute apregraves le menu (puisque nous creacuteons les widgets dans lordre ougrave ilfaut les inteacutegrer agrave linterface (8) ) nous devons creacuteer le GtkTextView (seul lappel agrave gtk_text_view_new est deacuteplaceacute)

XII-C - Code source

chapitre12zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 36 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIII - Les barres doutils

XIII-A - Aperccedilu

Cliquez pour agrandir

XIII-B - Creacuteation dune barre doutils

La creacuteation dune barre doutils ressemble fort agrave celle dun menu en plus simple puisquil ny a pas de sous menu on creacutee notre barre doutils (gtk_toolbar_new) puis les eacuteleacutements de la barre pour cela on utilise des boutons(gtk_tool_button_new_from_stock) que lon inseacutere dans la barre (gtk_toolbar_insert) Pas conseacutequent notre fichierbarreoutilsc ressemble agrave menuc

barreoutilscinclude ltgtkgtkhgtinclude callbackhinclude barreoutilsh

static void toolbar_item_new (GtkToolbar const gchar GCallback gpointer)

GtkToolbar toolbar_new (gpointer user_data) GtkWidget p_toolbar = NULL

p_toolbar = gtk_toolbar_new () toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_NEW G_CALLBACK (cb_new) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_OPEN G_CALLBACK (cb_open) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE G_CALLBACK (cb_save) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE_AS G_CALLBACK (cb_saveas) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_CLOSE G_CALLBACK (cb_close) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_QUIT G_CALLBACK (cb_quit) user_data) return GTK_TOOLBAR (p_toolbar)

static void toolbar_item_new (GtkToolbar p_toolbar const gchar stock_id GCallback callback gpointer user_data) GtkToolItem p_tool_item = NULL

p_tool_item = gtk_tool_button_new_from_stock (stock_id) g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data) gtk_toolbar_insert (p_toolbar p_tool_item -1)

Le code nest pas complet car lorsque jexeacutecute le programme GTK+ affiche en plus des icocircnes le texte sous lesboutons Pour modifier cela il suffit dajouter une ligne de code

barreoutilsc gtk_toolbar_set_style (GTK_TOOLBAR (p_toolbar) GTK_TOOLBAR_ICONS)

Pourquoi gtk_tool_button_new_from_stock retourne un GtkToolItem et non un GtkWidgetcomme nous avons eacuteteacute habitueacute jusquagrave preacutesent Il sagit dune bizarrerie de GTK+ dontje ne connais pas la raison

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 37 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour anticiper un changement dinterface (dans GTK+ 30 peut ecirctre ) nous aurions pueacutecrire

Gtkwidget p_tool_item = NULL

p_tool_item = GTK_WIDGET (gtk_tool_button_new_from_stock (stock_id))g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data)gtk_toolbar_insert (p_toolbar GTK_TOOL_ITEM (p_tool_item) -1)

XIII-C - Code source

chapitre13zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 38 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIV - Les racourcis clavier

XIV-A - Aperccedilu

Cliquez pour agrandir

XIV-B - Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mneacutemoniques ces derniers permettent dacceacuteder agrave un eacuteleacutementseacutequentiellement alors que les raccourcis appellent une fonction si lutilisateur appuie simultaneacutement sur une ouplusieurs touches (geacuteneacuteralement de la forme ltModificateurgtTouche ougrave Modificateur repreacutesente les touches ShiftAlt et Control) Ce raccourci peut ecirctre attacheacute agrave un eacuteleacutement du menu mais ceci nest pas obligatoire

Les raccourcis sont regroupeacutes en groupe dans un GtkAccelGroup quil faut commencer par creacuteer

raccourciscinclude ltgtkgtkhgtinclude callbackhinclude raccourcish

GtkAccelGroup accel_group_new (gpointer user_data) GtkAccelGroup p_accel_group = NULL

p_accel_group = gtk_accel_group_new () return p_accel_group

Vous commencez agrave avoir lhabitude de cette organisation nous allons donc creacuteer une fonction qui va se chargerdajouter un raccourci au groupe

raccourciscstatic void accelerator_new (GtkAccelGroup p_accel_group const gchar accelerator const gchar accel_path GCallback callback gpointer user_data) guint key GdkModifierType mods GClosure closure = NULL

gtk_accelerator_parse (accelerator ampkey ampmods) closure = g_cclosure_new (callback user_data NULL) gtk_accel_group_connect (p_accel_group key mods GTK_ACCEL_VISIBLE closure) gtk_accel_map_add_entry (accel_path key mods)

La fonction gtk_accelerator_parse permet de deacutecomposer une chaicircne de caractegraveres de la forme ltControlgtF1 ouencore ltAltgtA en numeacutero de touche et modificateur

En plus des touches pour creacuteer un raccourci clavier nous avons besoin dune fonction agrave appeler lorsque lutilisateurappuie sur les touches speacutecifieacutees gtk_accel_group_connect attend une fonction du type GClosure regardons ladocumentation de gobject pour savoir agrave quoi cela correspond

typedef struct

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 23 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

documenthtypedef struct GList tous document_t actif docs_t

extern docs_t docs

endif not H_DOCUMENT

Et dans le fichier mainc

maincinclude documenth

docs_t docs = NULL NULL

Pour linstant la seule fonction qui modifie leacutetat dun document est la fonction open_file il faut donc inclure documenthdans callbackc et modifier leacutegegraverement la fonction pour enregistrer le document ouvert

callbackc if (g_file_get_contents (file_name ampcontents NULL NULL)) Pour linstant il faut allouer la memoire par la suite on modifira simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = g_strdup (file_name) Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = p_text_view Le document vient detre ouvert il nest donc pas modifie docsactif-gtsauve = TRUE

Ne soyez pas choqueacute si je ne teste pas le retour de la fonction g_malloc pour veacuterifier quilnest pas NULL En effet cette derniegravere met fin agrave lapplication si lallocation eacutechoue

VII-A - Code source

chapitre7zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 24 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VIII - Sauvegarder les modification

VIII-A - Aperccedilu

Cliquez pour agrandir

VIII-B - Enregistrer

Avant de pouvoir sauvegarder un document il faut quil soit modifieacute Comment savoir que le contenu du fichier a eacuteteacutemodifier Gracircce au signal changed du GtkTextBuffer que nous interceptons gracircce agrave la fonction cb_modifie

mainc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (p_text_view)) g_signal_connect (G_OBJECT (p_text_buffer) changed G_CALLBACK (cb_modifie) NULL)

Cette derniegravere modifie simplement le champ sauve du document

callbackcvoid cb_modifie (GtkWidget p_widget gpointer user_data) if (docsactif) docsactif-gtsauve = FALSE

Pour la sauvegarde il faut distinguer deux cas soit il sagit de la premiegravere sauvegarde du fichier il faut alors demanderle nom du fichier agrave lutilisateur (cela ressemble fortement agrave louverture dun fichier) soit le fichier est deacutejagrave preacutesent surle disque il suffit de remplacer son contenu par celui du GtkTextViewer Nous avons convenu quun fichier qui neacutetaitpas encore enregistreacute avait sa proprieacuteteacute chemin agrave NULL

Bien sucircr cela na lieu que si un fichier est ouvert et quil a eacuteteacute modifieacute depuis sa derniegravere sauvegarde

callbackcvoid cb_save (GtkWidget p_widget gpointer user_data) if (docsactif) if (docsactif-gtsauve) Le fichier na pas encore ete enregistre if (docsactif-gtchemin) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Sauvegarder le fichier NULL GTK_FILE_CHOOSER_ACTION_SAVE GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_SAVE GTK_RESPONSE_ACCEPT NULL) if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 25 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc docsactif-gtchemin = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) gtk_widget_destroy (p_dialog) Soit le fichier a deja ete enregistre soit lutilisateur vient de nous fournir son nouvel enplacement on peut donc lenregistrer if (docsactif-gtchemin) else print_warning (Aucun document ouvert)

Il nous reste plus quagrave reacutecupeacuterer le contenu du GtkTextViewer et le copier dans le fichier chemin sans oublier dereconvertir le texte dans le codage local

callbackc FILE fichier = NULL

fichier = fopen (docsactif-gtchemin w) if (fichier) gchar contents = NULL gchar locale = NULL GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) contents = gtk_text_buffer_get_text (p_text_buffer ampstart ampend FALSE) locale = g_locale_from_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL fprintf (fichier s locale) g_free (locale) locale = NULL fclose (fichier) fichier = NULL docsactif-gtsauve = TRUE else print_warning (Impossible de sauvegarder le fichier s docsactif-gtchemin)

Le dernier paramegravetre de la fonction gtk_text_buffer_get_text est mis agrave FALSE car nous ne voulons pas enregistrerles caractegraveres invisibles preacutesent dans le GtkTextBuffer Ces caractegraveres servent agrave mettre en forme le texte (taillecouleur) nous pourrions creacuteer un nouveau format de fichier pour enregistrer la mise en forme

VIII-C - Enregistrer sous

Pour enregistrer notre document sous un autre nom il suffit de faire croire agrave cb_save que le document na pas encoreeacutetait enregistreacute tout simplement en changeant chemin agrave NULL et sauve agrave FALSE

callbackcvoid cb_saveas (GtkWidget p_widget gpointer user_data)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 26 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (docsactif) document_t tmp = docsactif

docsactif-gtchemin = NULL docsactif-gtsauve = FALSE cb_save (p_widget user_data) if (docsactif-gtsauve) (docsactif) = tmp else print_warning (Aucun document ouvert)

Il ne faut pas oublier que lutilisateur peut annuler lenregistrement de ce fait nous sauvegardons leacutetat du documentet si la sauvegarde na pas eu lieu on le restaure

VIII-D - Code source

chapitre8zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 27 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IX - Creacuteer un nouveau document

IX-A - Aperccedilu

Cliquez pour agrandir

IX-B - Nouveau fichier

Maintenant que lutilisateur peut ouvrir et fermer un fichier il est inteacuteressant de lui donner la possibiliteacute den creacuteerun nouveau Je ne reviens pas sur la creacuteation du bouton (ccedila devrait deacutejagrave ecirctre fait D) passons directement agrave lafonction cb_new

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) Pour linstant il faut allouer la memoire par la suite on modifiera simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = NULL Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = GTK_TEXT_VIEW (user_data) Le document vient detre creer il nest donc pas modifie docsactif-gtsauve = TRUE gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Je ne sais pas vous mais pour ma part jai fait un copiercoller de la fonction open_file Et oui ouvrir un document peutse reacutesumer agrave creacuteer un document vide puis remplir le GtkTextView avec le fichier souhaiteacute On peut donc simplifiernotre fonction open_file ainsi

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

cb_new (NULL p_text_view) gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE) p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1) Nous sommes obliges de remetre sauve a TRUE car linsertion du contenu du fichier dans le GtkTextView a appele cb_modfie docsactif-gtsauve = TRUE else print_warning (Impossible douvrir le fichier sn file_name)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 28 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc

Cest beau la factorisation du code Par contre nous sommes obligeacutes de remettre sauve agrave TRUE car nous avonsmodifieacute le GtkTextBuffer

IX-C - Code source

chapitre9zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 29 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

X - Fermer

X-A - Aperccedilu

Cliquez pour agrandir

X-B - Fermer un fichier

Maintenant que nous allouons de la meacutemoire il faut la libeacuterer agrave un endroit Logiquement cela va ecirctre fait agrave la fermeturedu document en guise dexercice je vous laisse creacuteer le bouton dans notre boicircte agrave bouton

Allez je vous aide le stock id correspondant est GTK_STOCK_CLOSE

Voilagrave maintenant si tout cest bien passeacute vous devriez ecirctre arriveacute dans le fichier callbackc avec quelque choseressemblant agrave

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data)

Lorsque lon ferme un document il faut vider le GtkTextView (avec les onglets on se contentera de le supprimer)pour cela il faut reacutecupeacuterer le deacutebut et la fin du GtkTextBuffer et demander agrave GTK+ de supprimer tout ce qui ce trouveentre les deux iteacuterateurs

callbackc Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) gtk_text_buffer_delete (p_text_buffer ampstart ampend) else print_warning (Aucun document ouvert)

Bien sucircr il ne faut pas oublier de libeacuterer la meacutemoire

callbackc g_free (docsactif-gtchemin) docsactif-gtchemin = NULL docsactif-gtp_text_view = NULL g_free (docsactif) docsactif = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 30 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour symboliser la fermeture dun document nous deacutesactivons le GtkTextView lors de la fermeture (ne pas oublierde le faire aussi dans mainc)

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) FALSE)

Et nous le reacuteactivons lors de louverture si celle si reacuteussie

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Lorsque lutilisateur quitte lapplication il faut bien sucircr fermer le document sil y en a un ouvert

void cb_quit (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data) gtk_main_quit()

Et aussi lorsquil creacuteeacute un nouveau document (et par conseacutequent lorsquil ouvre un fichier puisque lon fait appel agravecb_new)

void cb_new (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data)

X-C - Enregistrer avant de fermer

Si le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde geacuteneacuteralement le programme le signale agrave lutilisateur etlui propose de sauvegarder ou dannuler la fermeture Pour se faire nous devons modifier la fonction cb_close avantde fermer le document nous allons afficher une boicircte de dialogue

Pour creacuteer une boicircte de dialogue simplement il existe la classe GtkDialog et comme nous avons besoin de boutons(pour que lutilisateur fasse son choix) nous allons creacuteer notre boicircte avec la fonction

GtkWidget gtk_dialog_new_with_buttons (const gchar title GtkWindow parent GtkDialogFlags flags const gchar first_button_text )

Nous retrouvons les mecircmes options que pour le GtkFileChooserDialog mis agrave part option du type GtkDialogFlags

typedef enum GTK_DIALOG_MODAL = 1 ltlt 0 appel gtk_window_set_modal (win TRUE) GTK_DIALOG_DESTROY_WITH_PARENT = 1 ltlt 1 appel gtk_window_set_destroy_with_parent () GTK_DIALOG_NO_SEPARATOR = 1 ltlt 2 Pas de barre de separation au dessus des boutons GtkDialogFlags

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 31 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Nous nous contenterons de rendre notre fenecirctre modale (7)

Pour avoir accegraves agrave notre fenecirctre principale nous ajoutons un champs p_main_window agrave notre structure globaledocs_t que nous initialisons dans la fonction main

mainc docsp_main_window = GTK_WINDOW (p_window)

Il nous reste plus qua creacuteer notre boicircte de dialogue avec trois boutons Oui Non Annuler

callbackc if (docsactif-gtsauve) GtkWidget p_dialog = NULL

p_dialog = gtk_dialog_new_with_buttons (Sauvegarder docsp_main_window GTK_DIALOG_MODAL GTK_STOCK_YES GTK_RESPONSE_YES GTK_STOCK_NO GTK_RESPONSE_NO GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL NULL)

Nous obtenons donc une structure de type GtkDialog

typedef struct GtkWidget vbox GtkWidget action_area GtkDialog

Nous remarquons que cette structure contient deux membres qui permettent dacceacuteder agrave une GtkBox ougrave nous allonsajouter le contenu de la fenecirctre et agrave la partie contenant les boutons

Ensuite la construction de la fenecirctre est identique agrave celle de la fenecirctre principale ici nous nous contenterons dajouterun GtkLabel

callbackc GtkWidget p_label = NULL p_label = gtk_label_new (Voulez-vous sauvegarder les modifications ) gtk_box_pack_start (GTK_BOX (GTK_DIALOG (p_dialog)-gtvbox) p_label TRUE TRUE 0)

Une fois notre fenecirctre precircte il suffit de faire appel agrave la fonction gtk_dialog_run qui va afficher notre GtkDialog et nousretourner le reacuteponse id correspondant au bouton cliqueacute par lutilisateur

callbackc switch (gtk_dialog_run (GTK_DIALOG (p_dialog))) case GTK_RESPONSE_YES cb_save (p_widget user_data) break case GTK_RESPONSE_NO break case GTK_RESPONSE_CANCEL gtk_widget_destroy (p_dialog) return break

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 32 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc gtk_widget_destroy (p_dialog)

Si lutilisateur clique sur non on ne fait rien (le document sera simplement fermeacute) sur oui on enregistre avant defermer et pour finir sil annule on quitte la fonction

X-D - Code source

chapitre10zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 33 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XI - Les barres de deacutefilement

XI-A - Aperccedilu

Cliquez pour agrandir

XI-B - Ajouter des barres de deacutefilement

Apregraves le dernier chapitre quelque peu laborieux voici une partie plus simple mais qui va rendre notre applicationplus pratique En effet si vous avez essayeacute douvrir un fichier de grande taille vous avez pu remarquer que pourpouvoir lire la fin du fichier il fallait utiliser les touches du clavier pas tregraves convivial

Pour rendre la navigation plus aiseacutee on utilise des barres de deacutefilement

mainc GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_scrolled_window TRUE TRUE 0)

Creation de la zone de texte gtk_container_add (GTK_CONTAINER (p_scrolled_window) p_text_view)

Le constructeur de notre GtkScrolledWindow prend en argument deux GtkAdjustment qui permettent de deacutefinirdiffeacuterentes proprieacuteteacutes de la barre de deacutefilement (taille dune page la position de deacutepart) nous laissons GTK+ faireen passant NULL

Cest un bon deacutebut mais estheacutetiquement on peut faire mieux mecircme sil nest pas utile davoir une barre de deacutefilementelle est quand mecircme afficheacutee On peut demander agrave GTK+ de les afficher que si cela est neacutecessaire

mainc gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC)

En fait nous avons de la chance car la classe GtkTextView fait partie des widget qui supporte de faccedilon native les barresde deacutefilement Comment le savoir Ce genre de widget possegravede une ou deux proprieacuteteacutes de type GtkAdjustment (unepour la barre verticale lautre pour la barre horizontale) Actuellement seulement trois classes en sont capables lesGtkTextView les GtkTreeView et les GtkLayout

Comment faire pour les autres widgets Il faut passer par une classe adaptateur GtkViewport afin de creacuteer lesGtkAdjustment

XI-C - Code source

chapitre11zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 34 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XII - Les menus

XII-A - Aperccedilu

Cliquez pour agrandir

XII-B - Creacuteation du menu

Pour simplifier nous avons utiliseacute des boutons pour permettre agrave lutilisateur de creacuteer un document ouvrir un fichierMais il est plus courant dutiliser un menu pour afficher ces options GTK+ propose trois maniegraveres de creacuteer un menu

bull GtkItemFactory cette meacutethode est obsolegravete depuis la version 24 de GTK+

bull GtkUIManager cest ce quon appel une usine agrave gaz pour en savoir plus vous pouvez vous reporter aututoriel Utilisation de GtkUIManager

bull GtkMenu cest ce widget que nous allons eacutetudier il permet de creacuteer un menu manuellement (agrave lopposeacute deGtkUIManager)

Un menu selon GTK+ est composeacute de plusieurs eacuteleacutements

bull GtkMenuBar la barre de menu elle-mecircme

bull GtkMenu la partie deacuteroulante qui contient les diffeacuterents eacuteleacutements

bull GtkMenuItem cest sur ce widget que lutilisateur clique pour lancer une action

Pour commencer faisons linventaire de ce que nous avons besoin

bull Un GtkMenuBar qui sert de base au menu

bull Un GtkMenu pour commencer nous nous aurons dun menu Fichier

bull Six GtkMenuItem pour remplacer nos six boutons

Commenccedilons par la creacuteation du menu nous mettons ce code dans un nouveau fichier dont seul la fonction menu_newsera accessible

menucGtkMenuBar menu_new (gpointer user_data) GtkWidget p_menu_bar = NULL

p_menu_bar = gtk_menu_bar_new () return GTK_MENU_BAR (p_menu_bar)

Le paramegravetre user_data nous servira lors de la connexion des callbacks (nous en avons besoin pour les fonctionscb_new et cb_open)

Ensuite nous allons creacuteer notre sous menu Fichier

menuc Menu Fichier

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 35 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

menuc GtkWidget p_menu = NULL GtkWidget p_menu_item = NULL

p_menu = gtk_menu_new () p_menu_item = gtk_menu_item_new_with_mnemonic (_Fichier) gtk_menu_item_set_submenu (GTK_MENU_ITEM (p_menu_item) p_menu) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu_bar) p_menu_item) return GTK_MENU_BAR (p_menu_bar)

Un sous menu est en fait un GtkMenuItem auquel on assigne un GtkMenu Il faut bien sucircr terminer la creacuteation dusous-menu en lajoutant agrave la barre de menu

Pour finir nous creacuteons les eacuteleacutements du menu les GtkItemMenu Il existe plusieurs types deacuteleacutements (comparableaux diffeacuterents types de bouton) pour commencer nous nutiliserons que le type de base Comme cette opeacuteration estreacutepeacutetitive nous allons creacuteer une fonction pour le faire

menucstatic void menu_item_new (GtkMenu p_menu const gchar title GCallback callback gpointer user_data) GtkWidget p_menu_item = NULL

p_menu_item = gtk_menu_item_new_with_mnemonic (title) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu) p_menu_item) g_signal_connect (G_OBJECT (p_menu_item) activate callback user_data)

Pour permettre agrave lutilisateur dacceacuteder aux diffeacuterents eacuteleacutements du menu agrave laide de la touche ltAltgt nous utilisonsdes mneacutemoniques par exemple pour quitter leacutediteur il suffit de faite Alt+F puis Q Et voici le code pour creacuteer nossix eacuteleacutements du menu

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau G_CALLBACK (cb_new) user_data) menu_item_new (GTK_MENU (p_menu) _Ouvrir G_CALLBACK (cb_open) user_data) menu_item_new (GTK_MENU (p_menu) _Enregistrer G_CALLBACK (cb_save) user_data) menu_item_new (GTK_MENU (p_menu) Enregistrer _sous G_CALLBACK (cb_saveas) user_data) menu_item_new (GTK_MENU (p_menu) _Fermer G_CALLBACK (cb_close) user_data) menu_item_new (GTK_MENU (p_menu) _Quitter G_CALLBACK (cb_quit) user_data)

Voilagrave notre menu est creacuteeacute il nous reste plus quagrave linteacutegrer agrave notre fenecirctre

mainc gtk_box_pack_start (GTK_BOX (p_main_box) GTK_WIDGET (menu_new (p_text_view)) FALSE FALSE 0)

Le problegraveme cest que nous avons besoin de passer le GtkTextView lors de la creacuteation du menu (qui est utiliseacute par lesfonctions cb_new et cb_open) or celui-ci est creacuteeacute apregraves le menu (puisque nous creacuteons les widgets dans lordre ougrave ilfaut les inteacutegrer agrave linterface (8) ) nous devons creacuteer le GtkTextView (seul lappel agrave gtk_text_view_new est deacuteplaceacute)

XII-C - Code source

chapitre12zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 36 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIII - Les barres doutils

XIII-A - Aperccedilu

Cliquez pour agrandir

XIII-B - Creacuteation dune barre doutils

La creacuteation dune barre doutils ressemble fort agrave celle dun menu en plus simple puisquil ny a pas de sous menu on creacutee notre barre doutils (gtk_toolbar_new) puis les eacuteleacutements de la barre pour cela on utilise des boutons(gtk_tool_button_new_from_stock) que lon inseacutere dans la barre (gtk_toolbar_insert) Pas conseacutequent notre fichierbarreoutilsc ressemble agrave menuc

barreoutilscinclude ltgtkgtkhgtinclude callbackhinclude barreoutilsh

static void toolbar_item_new (GtkToolbar const gchar GCallback gpointer)

GtkToolbar toolbar_new (gpointer user_data) GtkWidget p_toolbar = NULL

p_toolbar = gtk_toolbar_new () toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_NEW G_CALLBACK (cb_new) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_OPEN G_CALLBACK (cb_open) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE G_CALLBACK (cb_save) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE_AS G_CALLBACK (cb_saveas) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_CLOSE G_CALLBACK (cb_close) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_QUIT G_CALLBACK (cb_quit) user_data) return GTK_TOOLBAR (p_toolbar)

static void toolbar_item_new (GtkToolbar p_toolbar const gchar stock_id GCallback callback gpointer user_data) GtkToolItem p_tool_item = NULL

p_tool_item = gtk_tool_button_new_from_stock (stock_id) g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data) gtk_toolbar_insert (p_toolbar p_tool_item -1)

Le code nest pas complet car lorsque jexeacutecute le programme GTK+ affiche en plus des icocircnes le texte sous lesboutons Pour modifier cela il suffit dajouter une ligne de code

barreoutilsc gtk_toolbar_set_style (GTK_TOOLBAR (p_toolbar) GTK_TOOLBAR_ICONS)

Pourquoi gtk_tool_button_new_from_stock retourne un GtkToolItem et non un GtkWidgetcomme nous avons eacuteteacute habitueacute jusquagrave preacutesent Il sagit dune bizarrerie de GTK+ dontje ne connais pas la raison

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 37 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour anticiper un changement dinterface (dans GTK+ 30 peut ecirctre ) nous aurions pueacutecrire

Gtkwidget p_tool_item = NULL

p_tool_item = GTK_WIDGET (gtk_tool_button_new_from_stock (stock_id))g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data)gtk_toolbar_insert (p_toolbar GTK_TOOL_ITEM (p_tool_item) -1)

XIII-C - Code source

chapitre13zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 38 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIV - Les racourcis clavier

XIV-A - Aperccedilu

Cliquez pour agrandir

XIV-B - Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mneacutemoniques ces derniers permettent dacceacuteder agrave un eacuteleacutementseacutequentiellement alors que les raccourcis appellent une fonction si lutilisateur appuie simultaneacutement sur une ouplusieurs touches (geacuteneacuteralement de la forme ltModificateurgtTouche ougrave Modificateur repreacutesente les touches ShiftAlt et Control) Ce raccourci peut ecirctre attacheacute agrave un eacuteleacutement du menu mais ceci nest pas obligatoire

Les raccourcis sont regroupeacutes en groupe dans un GtkAccelGroup quil faut commencer par creacuteer

raccourciscinclude ltgtkgtkhgtinclude callbackhinclude raccourcish

GtkAccelGroup accel_group_new (gpointer user_data) GtkAccelGroup p_accel_group = NULL

p_accel_group = gtk_accel_group_new () return p_accel_group

Vous commencez agrave avoir lhabitude de cette organisation nous allons donc creacuteer une fonction qui va se chargerdajouter un raccourci au groupe

raccourciscstatic void accelerator_new (GtkAccelGroup p_accel_group const gchar accelerator const gchar accel_path GCallback callback gpointer user_data) guint key GdkModifierType mods GClosure closure = NULL

gtk_accelerator_parse (accelerator ampkey ampmods) closure = g_cclosure_new (callback user_data NULL) gtk_accel_group_connect (p_accel_group key mods GTK_ACCEL_VISIBLE closure) gtk_accel_map_add_entry (accel_path key mods)

La fonction gtk_accelerator_parse permet de deacutecomposer une chaicircne de caractegraveres de la forme ltControlgtF1 ouencore ltAltgtA en numeacutero de touche et modificateur

En plus des touches pour creacuteer un raccourci clavier nous avons besoin dune fonction agrave appeler lorsque lutilisateurappuie sur les touches speacutecifieacutees gtk_accel_group_connect attend une fonction du type GClosure regardons ladocumentation de gobject pour savoir agrave quoi cela correspond

typedef struct

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 24 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

VIII - Sauvegarder les modification

VIII-A - Aperccedilu

Cliquez pour agrandir

VIII-B - Enregistrer

Avant de pouvoir sauvegarder un document il faut quil soit modifieacute Comment savoir que le contenu du fichier a eacuteteacutemodifier Gracircce au signal changed du GtkTextBuffer que nous interceptons gracircce agrave la fonction cb_modifie

mainc GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (p_text_view)) g_signal_connect (G_OBJECT (p_text_buffer) changed G_CALLBACK (cb_modifie) NULL)

Cette derniegravere modifie simplement le champ sauve du document

callbackcvoid cb_modifie (GtkWidget p_widget gpointer user_data) if (docsactif) docsactif-gtsauve = FALSE

Pour la sauvegarde il faut distinguer deux cas soit il sagit de la premiegravere sauvegarde du fichier il faut alors demanderle nom du fichier agrave lutilisateur (cela ressemble fortement agrave louverture dun fichier) soit le fichier est deacutejagrave preacutesent surle disque il suffit de remplacer son contenu par celui du GtkTextViewer Nous avons convenu quun fichier qui neacutetaitpas encore enregistreacute avait sa proprieacuteteacute chemin agrave NULL

Bien sucircr cela na lieu que si un fichier est ouvert et quil a eacuteteacute modifieacute depuis sa derniegravere sauvegarde

callbackcvoid cb_save (GtkWidget p_widget gpointer user_data) if (docsactif) if (docsactif-gtsauve) Le fichier na pas encore ete enregistre if (docsactif-gtchemin) GtkWidget p_dialog = NULL

p_dialog = gtk_file_chooser_dialog_new (Sauvegarder le fichier NULL GTK_FILE_CHOOSER_ACTION_SAVE GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL GTK_STOCK_SAVE GTK_RESPONSE_ACCEPT NULL) if (gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 25 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc docsactif-gtchemin = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) gtk_widget_destroy (p_dialog) Soit le fichier a deja ete enregistre soit lutilisateur vient de nous fournir son nouvel enplacement on peut donc lenregistrer if (docsactif-gtchemin) else print_warning (Aucun document ouvert)

Il nous reste plus quagrave reacutecupeacuterer le contenu du GtkTextViewer et le copier dans le fichier chemin sans oublier dereconvertir le texte dans le codage local

callbackc FILE fichier = NULL

fichier = fopen (docsactif-gtchemin w) if (fichier) gchar contents = NULL gchar locale = NULL GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) contents = gtk_text_buffer_get_text (p_text_buffer ampstart ampend FALSE) locale = g_locale_from_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL fprintf (fichier s locale) g_free (locale) locale = NULL fclose (fichier) fichier = NULL docsactif-gtsauve = TRUE else print_warning (Impossible de sauvegarder le fichier s docsactif-gtchemin)

Le dernier paramegravetre de la fonction gtk_text_buffer_get_text est mis agrave FALSE car nous ne voulons pas enregistrerles caractegraveres invisibles preacutesent dans le GtkTextBuffer Ces caractegraveres servent agrave mettre en forme le texte (taillecouleur) nous pourrions creacuteer un nouveau format de fichier pour enregistrer la mise en forme

VIII-C - Enregistrer sous

Pour enregistrer notre document sous un autre nom il suffit de faire croire agrave cb_save que le document na pas encoreeacutetait enregistreacute tout simplement en changeant chemin agrave NULL et sauve agrave FALSE

callbackcvoid cb_saveas (GtkWidget p_widget gpointer user_data)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 26 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (docsactif) document_t tmp = docsactif

docsactif-gtchemin = NULL docsactif-gtsauve = FALSE cb_save (p_widget user_data) if (docsactif-gtsauve) (docsactif) = tmp else print_warning (Aucun document ouvert)

Il ne faut pas oublier que lutilisateur peut annuler lenregistrement de ce fait nous sauvegardons leacutetat du documentet si la sauvegarde na pas eu lieu on le restaure

VIII-D - Code source

chapitre8zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 27 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IX - Creacuteer un nouveau document

IX-A - Aperccedilu

Cliquez pour agrandir

IX-B - Nouveau fichier

Maintenant que lutilisateur peut ouvrir et fermer un fichier il est inteacuteressant de lui donner la possibiliteacute den creacuteerun nouveau Je ne reviens pas sur la creacuteation du bouton (ccedila devrait deacutejagrave ecirctre fait D) passons directement agrave lafonction cb_new

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) Pour linstant il faut allouer la memoire par la suite on modifiera simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = NULL Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = GTK_TEXT_VIEW (user_data) Le document vient detre creer il nest donc pas modifie docsactif-gtsauve = TRUE gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Je ne sais pas vous mais pour ma part jai fait un copiercoller de la fonction open_file Et oui ouvrir un document peutse reacutesumer agrave creacuteer un document vide puis remplir le GtkTextView avec le fichier souhaiteacute On peut donc simplifiernotre fonction open_file ainsi

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

cb_new (NULL p_text_view) gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE) p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1) Nous sommes obliges de remetre sauve a TRUE car linsertion du contenu du fichier dans le GtkTextView a appele cb_modfie docsactif-gtsauve = TRUE else print_warning (Impossible douvrir le fichier sn file_name)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 28 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc

Cest beau la factorisation du code Par contre nous sommes obligeacutes de remettre sauve agrave TRUE car nous avonsmodifieacute le GtkTextBuffer

IX-C - Code source

chapitre9zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 29 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

X - Fermer

X-A - Aperccedilu

Cliquez pour agrandir

X-B - Fermer un fichier

Maintenant que nous allouons de la meacutemoire il faut la libeacuterer agrave un endroit Logiquement cela va ecirctre fait agrave la fermeturedu document en guise dexercice je vous laisse creacuteer le bouton dans notre boicircte agrave bouton

Allez je vous aide le stock id correspondant est GTK_STOCK_CLOSE

Voilagrave maintenant si tout cest bien passeacute vous devriez ecirctre arriveacute dans le fichier callbackc avec quelque choseressemblant agrave

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data)

Lorsque lon ferme un document il faut vider le GtkTextView (avec les onglets on se contentera de le supprimer)pour cela il faut reacutecupeacuterer le deacutebut et la fin du GtkTextBuffer et demander agrave GTK+ de supprimer tout ce qui ce trouveentre les deux iteacuterateurs

callbackc Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) gtk_text_buffer_delete (p_text_buffer ampstart ampend) else print_warning (Aucun document ouvert)

Bien sucircr il ne faut pas oublier de libeacuterer la meacutemoire

callbackc g_free (docsactif-gtchemin) docsactif-gtchemin = NULL docsactif-gtp_text_view = NULL g_free (docsactif) docsactif = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 30 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour symboliser la fermeture dun document nous deacutesactivons le GtkTextView lors de la fermeture (ne pas oublierde le faire aussi dans mainc)

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) FALSE)

Et nous le reacuteactivons lors de louverture si celle si reacuteussie

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Lorsque lutilisateur quitte lapplication il faut bien sucircr fermer le document sil y en a un ouvert

void cb_quit (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data) gtk_main_quit()

Et aussi lorsquil creacuteeacute un nouveau document (et par conseacutequent lorsquil ouvre un fichier puisque lon fait appel agravecb_new)

void cb_new (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data)

X-C - Enregistrer avant de fermer

Si le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde geacuteneacuteralement le programme le signale agrave lutilisateur etlui propose de sauvegarder ou dannuler la fermeture Pour se faire nous devons modifier la fonction cb_close avantde fermer le document nous allons afficher une boicircte de dialogue

Pour creacuteer une boicircte de dialogue simplement il existe la classe GtkDialog et comme nous avons besoin de boutons(pour que lutilisateur fasse son choix) nous allons creacuteer notre boicircte avec la fonction

GtkWidget gtk_dialog_new_with_buttons (const gchar title GtkWindow parent GtkDialogFlags flags const gchar first_button_text )

Nous retrouvons les mecircmes options que pour le GtkFileChooserDialog mis agrave part option du type GtkDialogFlags

typedef enum GTK_DIALOG_MODAL = 1 ltlt 0 appel gtk_window_set_modal (win TRUE) GTK_DIALOG_DESTROY_WITH_PARENT = 1 ltlt 1 appel gtk_window_set_destroy_with_parent () GTK_DIALOG_NO_SEPARATOR = 1 ltlt 2 Pas de barre de separation au dessus des boutons GtkDialogFlags

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 31 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Nous nous contenterons de rendre notre fenecirctre modale (7)

Pour avoir accegraves agrave notre fenecirctre principale nous ajoutons un champs p_main_window agrave notre structure globaledocs_t que nous initialisons dans la fonction main

mainc docsp_main_window = GTK_WINDOW (p_window)

Il nous reste plus qua creacuteer notre boicircte de dialogue avec trois boutons Oui Non Annuler

callbackc if (docsactif-gtsauve) GtkWidget p_dialog = NULL

p_dialog = gtk_dialog_new_with_buttons (Sauvegarder docsp_main_window GTK_DIALOG_MODAL GTK_STOCK_YES GTK_RESPONSE_YES GTK_STOCK_NO GTK_RESPONSE_NO GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL NULL)

Nous obtenons donc une structure de type GtkDialog

typedef struct GtkWidget vbox GtkWidget action_area GtkDialog

Nous remarquons que cette structure contient deux membres qui permettent dacceacuteder agrave une GtkBox ougrave nous allonsajouter le contenu de la fenecirctre et agrave la partie contenant les boutons

Ensuite la construction de la fenecirctre est identique agrave celle de la fenecirctre principale ici nous nous contenterons dajouterun GtkLabel

callbackc GtkWidget p_label = NULL p_label = gtk_label_new (Voulez-vous sauvegarder les modifications ) gtk_box_pack_start (GTK_BOX (GTK_DIALOG (p_dialog)-gtvbox) p_label TRUE TRUE 0)

Une fois notre fenecirctre precircte il suffit de faire appel agrave la fonction gtk_dialog_run qui va afficher notre GtkDialog et nousretourner le reacuteponse id correspondant au bouton cliqueacute par lutilisateur

callbackc switch (gtk_dialog_run (GTK_DIALOG (p_dialog))) case GTK_RESPONSE_YES cb_save (p_widget user_data) break case GTK_RESPONSE_NO break case GTK_RESPONSE_CANCEL gtk_widget_destroy (p_dialog) return break

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 32 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc gtk_widget_destroy (p_dialog)

Si lutilisateur clique sur non on ne fait rien (le document sera simplement fermeacute) sur oui on enregistre avant defermer et pour finir sil annule on quitte la fonction

X-D - Code source

chapitre10zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 33 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XI - Les barres de deacutefilement

XI-A - Aperccedilu

Cliquez pour agrandir

XI-B - Ajouter des barres de deacutefilement

Apregraves le dernier chapitre quelque peu laborieux voici une partie plus simple mais qui va rendre notre applicationplus pratique En effet si vous avez essayeacute douvrir un fichier de grande taille vous avez pu remarquer que pourpouvoir lire la fin du fichier il fallait utiliser les touches du clavier pas tregraves convivial

Pour rendre la navigation plus aiseacutee on utilise des barres de deacutefilement

mainc GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_scrolled_window TRUE TRUE 0)

Creation de la zone de texte gtk_container_add (GTK_CONTAINER (p_scrolled_window) p_text_view)

Le constructeur de notre GtkScrolledWindow prend en argument deux GtkAdjustment qui permettent de deacutefinirdiffeacuterentes proprieacuteteacutes de la barre de deacutefilement (taille dune page la position de deacutepart) nous laissons GTK+ faireen passant NULL

Cest un bon deacutebut mais estheacutetiquement on peut faire mieux mecircme sil nest pas utile davoir une barre de deacutefilementelle est quand mecircme afficheacutee On peut demander agrave GTK+ de les afficher que si cela est neacutecessaire

mainc gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC)

En fait nous avons de la chance car la classe GtkTextView fait partie des widget qui supporte de faccedilon native les barresde deacutefilement Comment le savoir Ce genre de widget possegravede une ou deux proprieacuteteacutes de type GtkAdjustment (unepour la barre verticale lautre pour la barre horizontale) Actuellement seulement trois classes en sont capables lesGtkTextView les GtkTreeView et les GtkLayout

Comment faire pour les autres widgets Il faut passer par une classe adaptateur GtkViewport afin de creacuteer lesGtkAdjustment

XI-C - Code source

chapitre11zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 34 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XII - Les menus

XII-A - Aperccedilu

Cliquez pour agrandir

XII-B - Creacuteation du menu

Pour simplifier nous avons utiliseacute des boutons pour permettre agrave lutilisateur de creacuteer un document ouvrir un fichierMais il est plus courant dutiliser un menu pour afficher ces options GTK+ propose trois maniegraveres de creacuteer un menu

bull GtkItemFactory cette meacutethode est obsolegravete depuis la version 24 de GTK+

bull GtkUIManager cest ce quon appel une usine agrave gaz pour en savoir plus vous pouvez vous reporter aututoriel Utilisation de GtkUIManager

bull GtkMenu cest ce widget que nous allons eacutetudier il permet de creacuteer un menu manuellement (agrave lopposeacute deGtkUIManager)

Un menu selon GTK+ est composeacute de plusieurs eacuteleacutements

bull GtkMenuBar la barre de menu elle-mecircme

bull GtkMenu la partie deacuteroulante qui contient les diffeacuterents eacuteleacutements

bull GtkMenuItem cest sur ce widget que lutilisateur clique pour lancer une action

Pour commencer faisons linventaire de ce que nous avons besoin

bull Un GtkMenuBar qui sert de base au menu

bull Un GtkMenu pour commencer nous nous aurons dun menu Fichier

bull Six GtkMenuItem pour remplacer nos six boutons

Commenccedilons par la creacuteation du menu nous mettons ce code dans un nouveau fichier dont seul la fonction menu_newsera accessible

menucGtkMenuBar menu_new (gpointer user_data) GtkWidget p_menu_bar = NULL

p_menu_bar = gtk_menu_bar_new () return GTK_MENU_BAR (p_menu_bar)

Le paramegravetre user_data nous servira lors de la connexion des callbacks (nous en avons besoin pour les fonctionscb_new et cb_open)

Ensuite nous allons creacuteer notre sous menu Fichier

menuc Menu Fichier

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 35 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

menuc GtkWidget p_menu = NULL GtkWidget p_menu_item = NULL

p_menu = gtk_menu_new () p_menu_item = gtk_menu_item_new_with_mnemonic (_Fichier) gtk_menu_item_set_submenu (GTK_MENU_ITEM (p_menu_item) p_menu) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu_bar) p_menu_item) return GTK_MENU_BAR (p_menu_bar)

Un sous menu est en fait un GtkMenuItem auquel on assigne un GtkMenu Il faut bien sucircr terminer la creacuteation dusous-menu en lajoutant agrave la barre de menu

Pour finir nous creacuteons les eacuteleacutements du menu les GtkItemMenu Il existe plusieurs types deacuteleacutements (comparableaux diffeacuterents types de bouton) pour commencer nous nutiliserons que le type de base Comme cette opeacuteration estreacutepeacutetitive nous allons creacuteer une fonction pour le faire

menucstatic void menu_item_new (GtkMenu p_menu const gchar title GCallback callback gpointer user_data) GtkWidget p_menu_item = NULL

p_menu_item = gtk_menu_item_new_with_mnemonic (title) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu) p_menu_item) g_signal_connect (G_OBJECT (p_menu_item) activate callback user_data)

Pour permettre agrave lutilisateur dacceacuteder aux diffeacuterents eacuteleacutements du menu agrave laide de la touche ltAltgt nous utilisonsdes mneacutemoniques par exemple pour quitter leacutediteur il suffit de faite Alt+F puis Q Et voici le code pour creacuteer nossix eacuteleacutements du menu

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau G_CALLBACK (cb_new) user_data) menu_item_new (GTK_MENU (p_menu) _Ouvrir G_CALLBACK (cb_open) user_data) menu_item_new (GTK_MENU (p_menu) _Enregistrer G_CALLBACK (cb_save) user_data) menu_item_new (GTK_MENU (p_menu) Enregistrer _sous G_CALLBACK (cb_saveas) user_data) menu_item_new (GTK_MENU (p_menu) _Fermer G_CALLBACK (cb_close) user_data) menu_item_new (GTK_MENU (p_menu) _Quitter G_CALLBACK (cb_quit) user_data)

Voilagrave notre menu est creacuteeacute il nous reste plus quagrave linteacutegrer agrave notre fenecirctre

mainc gtk_box_pack_start (GTK_BOX (p_main_box) GTK_WIDGET (menu_new (p_text_view)) FALSE FALSE 0)

Le problegraveme cest que nous avons besoin de passer le GtkTextView lors de la creacuteation du menu (qui est utiliseacute par lesfonctions cb_new et cb_open) or celui-ci est creacuteeacute apregraves le menu (puisque nous creacuteons les widgets dans lordre ougrave ilfaut les inteacutegrer agrave linterface (8) ) nous devons creacuteer le GtkTextView (seul lappel agrave gtk_text_view_new est deacuteplaceacute)

XII-C - Code source

chapitre12zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 36 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIII - Les barres doutils

XIII-A - Aperccedilu

Cliquez pour agrandir

XIII-B - Creacuteation dune barre doutils

La creacuteation dune barre doutils ressemble fort agrave celle dun menu en plus simple puisquil ny a pas de sous menu on creacutee notre barre doutils (gtk_toolbar_new) puis les eacuteleacutements de la barre pour cela on utilise des boutons(gtk_tool_button_new_from_stock) que lon inseacutere dans la barre (gtk_toolbar_insert) Pas conseacutequent notre fichierbarreoutilsc ressemble agrave menuc

barreoutilscinclude ltgtkgtkhgtinclude callbackhinclude barreoutilsh

static void toolbar_item_new (GtkToolbar const gchar GCallback gpointer)

GtkToolbar toolbar_new (gpointer user_data) GtkWidget p_toolbar = NULL

p_toolbar = gtk_toolbar_new () toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_NEW G_CALLBACK (cb_new) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_OPEN G_CALLBACK (cb_open) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE G_CALLBACK (cb_save) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE_AS G_CALLBACK (cb_saveas) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_CLOSE G_CALLBACK (cb_close) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_QUIT G_CALLBACK (cb_quit) user_data) return GTK_TOOLBAR (p_toolbar)

static void toolbar_item_new (GtkToolbar p_toolbar const gchar stock_id GCallback callback gpointer user_data) GtkToolItem p_tool_item = NULL

p_tool_item = gtk_tool_button_new_from_stock (stock_id) g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data) gtk_toolbar_insert (p_toolbar p_tool_item -1)

Le code nest pas complet car lorsque jexeacutecute le programme GTK+ affiche en plus des icocircnes le texte sous lesboutons Pour modifier cela il suffit dajouter une ligne de code

barreoutilsc gtk_toolbar_set_style (GTK_TOOLBAR (p_toolbar) GTK_TOOLBAR_ICONS)

Pourquoi gtk_tool_button_new_from_stock retourne un GtkToolItem et non un GtkWidgetcomme nous avons eacuteteacute habitueacute jusquagrave preacutesent Il sagit dune bizarrerie de GTK+ dontje ne connais pas la raison

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 37 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour anticiper un changement dinterface (dans GTK+ 30 peut ecirctre ) nous aurions pueacutecrire

Gtkwidget p_tool_item = NULL

p_tool_item = GTK_WIDGET (gtk_tool_button_new_from_stock (stock_id))g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data)gtk_toolbar_insert (p_toolbar GTK_TOOL_ITEM (p_tool_item) -1)

XIII-C - Code source

chapitre13zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 38 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIV - Les racourcis clavier

XIV-A - Aperccedilu

Cliquez pour agrandir

XIV-B - Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mneacutemoniques ces derniers permettent dacceacuteder agrave un eacuteleacutementseacutequentiellement alors que les raccourcis appellent une fonction si lutilisateur appuie simultaneacutement sur une ouplusieurs touches (geacuteneacuteralement de la forme ltModificateurgtTouche ougrave Modificateur repreacutesente les touches ShiftAlt et Control) Ce raccourci peut ecirctre attacheacute agrave un eacuteleacutement du menu mais ceci nest pas obligatoire

Les raccourcis sont regroupeacutes en groupe dans un GtkAccelGroup quil faut commencer par creacuteer

raccourciscinclude ltgtkgtkhgtinclude callbackhinclude raccourcish

GtkAccelGroup accel_group_new (gpointer user_data) GtkAccelGroup p_accel_group = NULL

p_accel_group = gtk_accel_group_new () return p_accel_group

Vous commencez agrave avoir lhabitude de cette organisation nous allons donc creacuteer une fonction qui va se chargerdajouter un raccourci au groupe

raccourciscstatic void accelerator_new (GtkAccelGroup p_accel_group const gchar accelerator const gchar accel_path GCallback callback gpointer user_data) guint key GdkModifierType mods GClosure closure = NULL

gtk_accelerator_parse (accelerator ampkey ampmods) closure = g_cclosure_new (callback user_data NULL) gtk_accel_group_connect (p_accel_group key mods GTK_ACCEL_VISIBLE closure) gtk_accel_map_add_entry (accel_path key mods)

La fonction gtk_accelerator_parse permet de deacutecomposer une chaicircne de caractegraveres de la forme ltControlgtF1 ouencore ltAltgtA en numeacutero de touche et modificateur

En plus des touches pour creacuteer un raccourci clavier nous avons besoin dune fonction agrave appeler lorsque lutilisateurappuie sur les touches speacutecifieacutees gtk_accel_group_connect attend une fonction du type GClosure regardons ladocumentation de gobject pour savoir agrave quoi cela correspond

typedef struct

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 25 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc docsactif-gtchemin = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog)) gtk_widget_destroy (p_dialog) Soit le fichier a deja ete enregistre soit lutilisateur vient de nous fournir son nouvel enplacement on peut donc lenregistrer if (docsactif-gtchemin) else print_warning (Aucun document ouvert)

Il nous reste plus quagrave reacutecupeacuterer le contenu du GtkTextViewer et le copier dans le fichier chemin sans oublier dereconvertir le texte dans le codage local

callbackc FILE fichier = NULL

fichier = fopen (docsactif-gtchemin w) if (fichier) gchar contents = NULL gchar locale = NULL GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) contents = gtk_text_buffer_get_text (p_text_buffer ampstart ampend FALSE) locale = g_locale_from_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL fprintf (fichier s locale) g_free (locale) locale = NULL fclose (fichier) fichier = NULL docsactif-gtsauve = TRUE else print_warning (Impossible de sauvegarder le fichier s docsactif-gtchemin)

Le dernier paramegravetre de la fonction gtk_text_buffer_get_text est mis agrave FALSE car nous ne voulons pas enregistrerles caractegraveres invisibles preacutesent dans le GtkTextBuffer Ces caractegraveres servent agrave mettre en forme le texte (taillecouleur) nous pourrions creacuteer un nouveau format de fichier pour enregistrer la mise en forme

VIII-C - Enregistrer sous

Pour enregistrer notre document sous un autre nom il suffit de faire croire agrave cb_save que le document na pas encoreeacutetait enregistreacute tout simplement en changeant chemin agrave NULL et sauve agrave FALSE

callbackcvoid cb_saveas (GtkWidget p_widget gpointer user_data)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 26 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (docsactif) document_t tmp = docsactif

docsactif-gtchemin = NULL docsactif-gtsauve = FALSE cb_save (p_widget user_data) if (docsactif-gtsauve) (docsactif) = tmp else print_warning (Aucun document ouvert)

Il ne faut pas oublier que lutilisateur peut annuler lenregistrement de ce fait nous sauvegardons leacutetat du documentet si la sauvegarde na pas eu lieu on le restaure

VIII-D - Code source

chapitre8zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 27 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IX - Creacuteer un nouveau document

IX-A - Aperccedilu

Cliquez pour agrandir

IX-B - Nouveau fichier

Maintenant que lutilisateur peut ouvrir et fermer un fichier il est inteacuteressant de lui donner la possibiliteacute den creacuteerun nouveau Je ne reviens pas sur la creacuteation du bouton (ccedila devrait deacutejagrave ecirctre fait D) passons directement agrave lafonction cb_new

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) Pour linstant il faut allouer la memoire par la suite on modifiera simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = NULL Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = GTK_TEXT_VIEW (user_data) Le document vient detre creer il nest donc pas modifie docsactif-gtsauve = TRUE gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Je ne sais pas vous mais pour ma part jai fait un copiercoller de la fonction open_file Et oui ouvrir un document peutse reacutesumer agrave creacuteer un document vide puis remplir le GtkTextView avec le fichier souhaiteacute On peut donc simplifiernotre fonction open_file ainsi

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

cb_new (NULL p_text_view) gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE) p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1) Nous sommes obliges de remetre sauve a TRUE car linsertion du contenu du fichier dans le GtkTextView a appele cb_modfie docsactif-gtsauve = TRUE else print_warning (Impossible douvrir le fichier sn file_name)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 28 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc

Cest beau la factorisation du code Par contre nous sommes obligeacutes de remettre sauve agrave TRUE car nous avonsmodifieacute le GtkTextBuffer

IX-C - Code source

chapitre9zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 29 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

X - Fermer

X-A - Aperccedilu

Cliquez pour agrandir

X-B - Fermer un fichier

Maintenant que nous allouons de la meacutemoire il faut la libeacuterer agrave un endroit Logiquement cela va ecirctre fait agrave la fermeturedu document en guise dexercice je vous laisse creacuteer le bouton dans notre boicircte agrave bouton

Allez je vous aide le stock id correspondant est GTK_STOCK_CLOSE

Voilagrave maintenant si tout cest bien passeacute vous devriez ecirctre arriveacute dans le fichier callbackc avec quelque choseressemblant agrave

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data)

Lorsque lon ferme un document il faut vider le GtkTextView (avec les onglets on se contentera de le supprimer)pour cela il faut reacutecupeacuterer le deacutebut et la fin du GtkTextBuffer et demander agrave GTK+ de supprimer tout ce qui ce trouveentre les deux iteacuterateurs

callbackc Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) gtk_text_buffer_delete (p_text_buffer ampstart ampend) else print_warning (Aucun document ouvert)

Bien sucircr il ne faut pas oublier de libeacuterer la meacutemoire

callbackc g_free (docsactif-gtchemin) docsactif-gtchemin = NULL docsactif-gtp_text_view = NULL g_free (docsactif) docsactif = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 30 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour symboliser la fermeture dun document nous deacutesactivons le GtkTextView lors de la fermeture (ne pas oublierde le faire aussi dans mainc)

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) FALSE)

Et nous le reacuteactivons lors de louverture si celle si reacuteussie

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Lorsque lutilisateur quitte lapplication il faut bien sucircr fermer le document sil y en a un ouvert

void cb_quit (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data) gtk_main_quit()

Et aussi lorsquil creacuteeacute un nouveau document (et par conseacutequent lorsquil ouvre un fichier puisque lon fait appel agravecb_new)

void cb_new (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data)

X-C - Enregistrer avant de fermer

Si le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde geacuteneacuteralement le programme le signale agrave lutilisateur etlui propose de sauvegarder ou dannuler la fermeture Pour se faire nous devons modifier la fonction cb_close avantde fermer le document nous allons afficher une boicircte de dialogue

Pour creacuteer une boicircte de dialogue simplement il existe la classe GtkDialog et comme nous avons besoin de boutons(pour que lutilisateur fasse son choix) nous allons creacuteer notre boicircte avec la fonction

GtkWidget gtk_dialog_new_with_buttons (const gchar title GtkWindow parent GtkDialogFlags flags const gchar first_button_text )

Nous retrouvons les mecircmes options que pour le GtkFileChooserDialog mis agrave part option du type GtkDialogFlags

typedef enum GTK_DIALOG_MODAL = 1 ltlt 0 appel gtk_window_set_modal (win TRUE) GTK_DIALOG_DESTROY_WITH_PARENT = 1 ltlt 1 appel gtk_window_set_destroy_with_parent () GTK_DIALOG_NO_SEPARATOR = 1 ltlt 2 Pas de barre de separation au dessus des boutons GtkDialogFlags

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 31 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Nous nous contenterons de rendre notre fenecirctre modale (7)

Pour avoir accegraves agrave notre fenecirctre principale nous ajoutons un champs p_main_window agrave notre structure globaledocs_t que nous initialisons dans la fonction main

mainc docsp_main_window = GTK_WINDOW (p_window)

Il nous reste plus qua creacuteer notre boicircte de dialogue avec trois boutons Oui Non Annuler

callbackc if (docsactif-gtsauve) GtkWidget p_dialog = NULL

p_dialog = gtk_dialog_new_with_buttons (Sauvegarder docsp_main_window GTK_DIALOG_MODAL GTK_STOCK_YES GTK_RESPONSE_YES GTK_STOCK_NO GTK_RESPONSE_NO GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL NULL)

Nous obtenons donc une structure de type GtkDialog

typedef struct GtkWidget vbox GtkWidget action_area GtkDialog

Nous remarquons que cette structure contient deux membres qui permettent dacceacuteder agrave une GtkBox ougrave nous allonsajouter le contenu de la fenecirctre et agrave la partie contenant les boutons

Ensuite la construction de la fenecirctre est identique agrave celle de la fenecirctre principale ici nous nous contenterons dajouterun GtkLabel

callbackc GtkWidget p_label = NULL p_label = gtk_label_new (Voulez-vous sauvegarder les modifications ) gtk_box_pack_start (GTK_BOX (GTK_DIALOG (p_dialog)-gtvbox) p_label TRUE TRUE 0)

Une fois notre fenecirctre precircte il suffit de faire appel agrave la fonction gtk_dialog_run qui va afficher notre GtkDialog et nousretourner le reacuteponse id correspondant au bouton cliqueacute par lutilisateur

callbackc switch (gtk_dialog_run (GTK_DIALOG (p_dialog))) case GTK_RESPONSE_YES cb_save (p_widget user_data) break case GTK_RESPONSE_NO break case GTK_RESPONSE_CANCEL gtk_widget_destroy (p_dialog) return break

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 32 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc gtk_widget_destroy (p_dialog)

Si lutilisateur clique sur non on ne fait rien (le document sera simplement fermeacute) sur oui on enregistre avant defermer et pour finir sil annule on quitte la fonction

X-D - Code source

chapitre10zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 33 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XI - Les barres de deacutefilement

XI-A - Aperccedilu

Cliquez pour agrandir

XI-B - Ajouter des barres de deacutefilement

Apregraves le dernier chapitre quelque peu laborieux voici une partie plus simple mais qui va rendre notre applicationplus pratique En effet si vous avez essayeacute douvrir un fichier de grande taille vous avez pu remarquer que pourpouvoir lire la fin du fichier il fallait utiliser les touches du clavier pas tregraves convivial

Pour rendre la navigation plus aiseacutee on utilise des barres de deacutefilement

mainc GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_scrolled_window TRUE TRUE 0)

Creation de la zone de texte gtk_container_add (GTK_CONTAINER (p_scrolled_window) p_text_view)

Le constructeur de notre GtkScrolledWindow prend en argument deux GtkAdjustment qui permettent de deacutefinirdiffeacuterentes proprieacuteteacutes de la barre de deacutefilement (taille dune page la position de deacutepart) nous laissons GTK+ faireen passant NULL

Cest un bon deacutebut mais estheacutetiquement on peut faire mieux mecircme sil nest pas utile davoir une barre de deacutefilementelle est quand mecircme afficheacutee On peut demander agrave GTK+ de les afficher que si cela est neacutecessaire

mainc gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC)

En fait nous avons de la chance car la classe GtkTextView fait partie des widget qui supporte de faccedilon native les barresde deacutefilement Comment le savoir Ce genre de widget possegravede une ou deux proprieacuteteacutes de type GtkAdjustment (unepour la barre verticale lautre pour la barre horizontale) Actuellement seulement trois classes en sont capables lesGtkTextView les GtkTreeView et les GtkLayout

Comment faire pour les autres widgets Il faut passer par une classe adaptateur GtkViewport afin de creacuteer lesGtkAdjustment

XI-C - Code source

chapitre11zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 34 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XII - Les menus

XII-A - Aperccedilu

Cliquez pour agrandir

XII-B - Creacuteation du menu

Pour simplifier nous avons utiliseacute des boutons pour permettre agrave lutilisateur de creacuteer un document ouvrir un fichierMais il est plus courant dutiliser un menu pour afficher ces options GTK+ propose trois maniegraveres de creacuteer un menu

bull GtkItemFactory cette meacutethode est obsolegravete depuis la version 24 de GTK+

bull GtkUIManager cest ce quon appel une usine agrave gaz pour en savoir plus vous pouvez vous reporter aututoriel Utilisation de GtkUIManager

bull GtkMenu cest ce widget que nous allons eacutetudier il permet de creacuteer un menu manuellement (agrave lopposeacute deGtkUIManager)

Un menu selon GTK+ est composeacute de plusieurs eacuteleacutements

bull GtkMenuBar la barre de menu elle-mecircme

bull GtkMenu la partie deacuteroulante qui contient les diffeacuterents eacuteleacutements

bull GtkMenuItem cest sur ce widget que lutilisateur clique pour lancer une action

Pour commencer faisons linventaire de ce que nous avons besoin

bull Un GtkMenuBar qui sert de base au menu

bull Un GtkMenu pour commencer nous nous aurons dun menu Fichier

bull Six GtkMenuItem pour remplacer nos six boutons

Commenccedilons par la creacuteation du menu nous mettons ce code dans un nouveau fichier dont seul la fonction menu_newsera accessible

menucGtkMenuBar menu_new (gpointer user_data) GtkWidget p_menu_bar = NULL

p_menu_bar = gtk_menu_bar_new () return GTK_MENU_BAR (p_menu_bar)

Le paramegravetre user_data nous servira lors de la connexion des callbacks (nous en avons besoin pour les fonctionscb_new et cb_open)

Ensuite nous allons creacuteer notre sous menu Fichier

menuc Menu Fichier

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 35 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

menuc GtkWidget p_menu = NULL GtkWidget p_menu_item = NULL

p_menu = gtk_menu_new () p_menu_item = gtk_menu_item_new_with_mnemonic (_Fichier) gtk_menu_item_set_submenu (GTK_MENU_ITEM (p_menu_item) p_menu) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu_bar) p_menu_item) return GTK_MENU_BAR (p_menu_bar)

Un sous menu est en fait un GtkMenuItem auquel on assigne un GtkMenu Il faut bien sucircr terminer la creacuteation dusous-menu en lajoutant agrave la barre de menu

Pour finir nous creacuteons les eacuteleacutements du menu les GtkItemMenu Il existe plusieurs types deacuteleacutements (comparableaux diffeacuterents types de bouton) pour commencer nous nutiliserons que le type de base Comme cette opeacuteration estreacutepeacutetitive nous allons creacuteer une fonction pour le faire

menucstatic void menu_item_new (GtkMenu p_menu const gchar title GCallback callback gpointer user_data) GtkWidget p_menu_item = NULL

p_menu_item = gtk_menu_item_new_with_mnemonic (title) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu) p_menu_item) g_signal_connect (G_OBJECT (p_menu_item) activate callback user_data)

Pour permettre agrave lutilisateur dacceacuteder aux diffeacuterents eacuteleacutements du menu agrave laide de la touche ltAltgt nous utilisonsdes mneacutemoniques par exemple pour quitter leacutediteur il suffit de faite Alt+F puis Q Et voici le code pour creacuteer nossix eacuteleacutements du menu

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau G_CALLBACK (cb_new) user_data) menu_item_new (GTK_MENU (p_menu) _Ouvrir G_CALLBACK (cb_open) user_data) menu_item_new (GTK_MENU (p_menu) _Enregistrer G_CALLBACK (cb_save) user_data) menu_item_new (GTK_MENU (p_menu) Enregistrer _sous G_CALLBACK (cb_saveas) user_data) menu_item_new (GTK_MENU (p_menu) _Fermer G_CALLBACK (cb_close) user_data) menu_item_new (GTK_MENU (p_menu) _Quitter G_CALLBACK (cb_quit) user_data)

Voilagrave notre menu est creacuteeacute il nous reste plus quagrave linteacutegrer agrave notre fenecirctre

mainc gtk_box_pack_start (GTK_BOX (p_main_box) GTK_WIDGET (menu_new (p_text_view)) FALSE FALSE 0)

Le problegraveme cest que nous avons besoin de passer le GtkTextView lors de la creacuteation du menu (qui est utiliseacute par lesfonctions cb_new et cb_open) or celui-ci est creacuteeacute apregraves le menu (puisque nous creacuteons les widgets dans lordre ougrave ilfaut les inteacutegrer agrave linterface (8) ) nous devons creacuteer le GtkTextView (seul lappel agrave gtk_text_view_new est deacuteplaceacute)

XII-C - Code source

chapitre12zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 36 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIII - Les barres doutils

XIII-A - Aperccedilu

Cliquez pour agrandir

XIII-B - Creacuteation dune barre doutils

La creacuteation dune barre doutils ressemble fort agrave celle dun menu en plus simple puisquil ny a pas de sous menu on creacutee notre barre doutils (gtk_toolbar_new) puis les eacuteleacutements de la barre pour cela on utilise des boutons(gtk_tool_button_new_from_stock) que lon inseacutere dans la barre (gtk_toolbar_insert) Pas conseacutequent notre fichierbarreoutilsc ressemble agrave menuc

barreoutilscinclude ltgtkgtkhgtinclude callbackhinclude barreoutilsh

static void toolbar_item_new (GtkToolbar const gchar GCallback gpointer)

GtkToolbar toolbar_new (gpointer user_data) GtkWidget p_toolbar = NULL

p_toolbar = gtk_toolbar_new () toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_NEW G_CALLBACK (cb_new) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_OPEN G_CALLBACK (cb_open) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE G_CALLBACK (cb_save) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE_AS G_CALLBACK (cb_saveas) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_CLOSE G_CALLBACK (cb_close) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_QUIT G_CALLBACK (cb_quit) user_data) return GTK_TOOLBAR (p_toolbar)

static void toolbar_item_new (GtkToolbar p_toolbar const gchar stock_id GCallback callback gpointer user_data) GtkToolItem p_tool_item = NULL

p_tool_item = gtk_tool_button_new_from_stock (stock_id) g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data) gtk_toolbar_insert (p_toolbar p_tool_item -1)

Le code nest pas complet car lorsque jexeacutecute le programme GTK+ affiche en plus des icocircnes le texte sous lesboutons Pour modifier cela il suffit dajouter une ligne de code

barreoutilsc gtk_toolbar_set_style (GTK_TOOLBAR (p_toolbar) GTK_TOOLBAR_ICONS)

Pourquoi gtk_tool_button_new_from_stock retourne un GtkToolItem et non un GtkWidgetcomme nous avons eacuteteacute habitueacute jusquagrave preacutesent Il sagit dune bizarrerie de GTK+ dontje ne connais pas la raison

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 37 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour anticiper un changement dinterface (dans GTK+ 30 peut ecirctre ) nous aurions pueacutecrire

Gtkwidget p_tool_item = NULL

p_tool_item = GTK_WIDGET (gtk_tool_button_new_from_stock (stock_id))g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data)gtk_toolbar_insert (p_toolbar GTK_TOOL_ITEM (p_tool_item) -1)

XIII-C - Code source

chapitre13zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 38 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIV - Les racourcis clavier

XIV-A - Aperccedilu

Cliquez pour agrandir

XIV-B - Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mneacutemoniques ces derniers permettent dacceacuteder agrave un eacuteleacutementseacutequentiellement alors que les raccourcis appellent une fonction si lutilisateur appuie simultaneacutement sur une ouplusieurs touches (geacuteneacuteralement de la forme ltModificateurgtTouche ougrave Modificateur repreacutesente les touches ShiftAlt et Control) Ce raccourci peut ecirctre attacheacute agrave un eacuteleacutement du menu mais ceci nest pas obligatoire

Les raccourcis sont regroupeacutes en groupe dans un GtkAccelGroup quil faut commencer par creacuteer

raccourciscinclude ltgtkgtkhgtinclude callbackhinclude raccourcish

GtkAccelGroup accel_group_new (gpointer user_data) GtkAccelGroup p_accel_group = NULL

p_accel_group = gtk_accel_group_new () return p_accel_group

Vous commencez agrave avoir lhabitude de cette organisation nous allons donc creacuteer une fonction qui va se chargerdajouter un raccourci au groupe

raccourciscstatic void accelerator_new (GtkAccelGroup p_accel_group const gchar accelerator const gchar accel_path GCallback callback gpointer user_data) guint key GdkModifierType mods GClosure closure = NULL

gtk_accelerator_parse (accelerator ampkey ampmods) closure = g_cclosure_new (callback user_data NULL) gtk_accel_group_connect (p_accel_group key mods GTK_ACCEL_VISIBLE closure) gtk_accel_map_add_entry (accel_path key mods)

La fonction gtk_accelerator_parse permet de deacutecomposer une chaicircne de caractegraveres de la forme ltControlgtF1 ouencore ltAltgtA en numeacutero de touche et modificateur

En plus des touches pour creacuteer un raccourci clavier nous avons besoin dune fonction agrave appeler lorsque lutilisateurappuie sur les touches speacutecifieacutees gtk_accel_group_connect attend une fonction du type GClosure regardons ladocumentation de gobject pour savoir agrave quoi cela correspond

typedef struct

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 26 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (docsactif) document_t tmp = docsactif

docsactif-gtchemin = NULL docsactif-gtsauve = FALSE cb_save (p_widget user_data) if (docsactif-gtsauve) (docsactif) = tmp else print_warning (Aucun document ouvert)

Il ne faut pas oublier que lutilisateur peut annuler lenregistrement de ce fait nous sauvegardons leacutetat du documentet si la sauvegarde na pas eu lieu on le restaure

VIII-D - Code source

chapitre8zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 27 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IX - Creacuteer un nouveau document

IX-A - Aperccedilu

Cliquez pour agrandir

IX-B - Nouveau fichier

Maintenant que lutilisateur peut ouvrir et fermer un fichier il est inteacuteressant de lui donner la possibiliteacute den creacuteerun nouveau Je ne reviens pas sur la creacuteation du bouton (ccedila devrait deacutejagrave ecirctre fait D) passons directement agrave lafonction cb_new

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) Pour linstant il faut allouer la memoire par la suite on modifiera simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = NULL Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = GTK_TEXT_VIEW (user_data) Le document vient detre creer il nest donc pas modifie docsactif-gtsauve = TRUE gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Je ne sais pas vous mais pour ma part jai fait un copiercoller de la fonction open_file Et oui ouvrir un document peutse reacutesumer agrave creacuteer un document vide puis remplir le GtkTextView avec le fichier souhaiteacute On peut donc simplifiernotre fonction open_file ainsi

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

cb_new (NULL p_text_view) gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE) p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1) Nous sommes obliges de remetre sauve a TRUE car linsertion du contenu du fichier dans le GtkTextView a appele cb_modfie docsactif-gtsauve = TRUE else print_warning (Impossible douvrir le fichier sn file_name)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 28 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc

Cest beau la factorisation du code Par contre nous sommes obligeacutes de remettre sauve agrave TRUE car nous avonsmodifieacute le GtkTextBuffer

IX-C - Code source

chapitre9zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 29 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

X - Fermer

X-A - Aperccedilu

Cliquez pour agrandir

X-B - Fermer un fichier

Maintenant que nous allouons de la meacutemoire il faut la libeacuterer agrave un endroit Logiquement cela va ecirctre fait agrave la fermeturedu document en guise dexercice je vous laisse creacuteer le bouton dans notre boicircte agrave bouton

Allez je vous aide le stock id correspondant est GTK_STOCK_CLOSE

Voilagrave maintenant si tout cest bien passeacute vous devriez ecirctre arriveacute dans le fichier callbackc avec quelque choseressemblant agrave

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data)

Lorsque lon ferme un document il faut vider le GtkTextView (avec les onglets on se contentera de le supprimer)pour cela il faut reacutecupeacuterer le deacutebut et la fin du GtkTextBuffer et demander agrave GTK+ de supprimer tout ce qui ce trouveentre les deux iteacuterateurs

callbackc Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) gtk_text_buffer_delete (p_text_buffer ampstart ampend) else print_warning (Aucun document ouvert)

Bien sucircr il ne faut pas oublier de libeacuterer la meacutemoire

callbackc g_free (docsactif-gtchemin) docsactif-gtchemin = NULL docsactif-gtp_text_view = NULL g_free (docsactif) docsactif = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 30 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour symboliser la fermeture dun document nous deacutesactivons le GtkTextView lors de la fermeture (ne pas oublierde le faire aussi dans mainc)

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) FALSE)

Et nous le reacuteactivons lors de louverture si celle si reacuteussie

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Lorsque lutilisateur quitte lapplication il faut bien sucircr fermer le document sil y en a un ouvert

void cb_quit (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data) gtk_main_quit()

Et aussi lorsquil creacuteeacute un nouveau document (et par conseacutequent lorsquil ouvre un fichier puisque lon fait appel agravecb_new)

void cb_new (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data)

X-C - Enregistrer avant de fermer

Si le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde geacuteneacuteralement le programme le signale agrave lutilisateur etlui propose de sauvegarder ou dannuler la fermeture Pour se faire nous devons modifier la fonction cb_close avantde fermer le document nous allons afficher une boicircte de dialogue

Pour creacuteer une boicircte de dialogue simplement il existe la classe GtkDialog et comme nous avons besoin de boutons(pour que lutilisateur fasse son choix) nous allons creacuteer notre boicircte avec la fonction

GtkWidget gtk_dialog_new_with_buttons (const gchar title GtkWindow parent GtkDialogFlags flags const gchar first_button_text )

Nous retrouvons les mecircmes options que pour le GtkFileChooserDialog mis agrave part option du type GtkDialogFlags

typedef enum GTK_DIALOG_MODAL = 1 ltlt 0 appel gtk_window_set_modal (win TRUE) GTK_DIALOG_DESTROY_WITH_PARENT = 1 ltlt 1 appel gtk_window_set_destroy_with_parent () GTK_DIALOG_NO_SEPARATOR = 1 ltlt 2 Pas de barre de separation au dessus des boutons GtkDialogFlags

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 31 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Nous nous contenterons de rendre notre fenecirctre modale (7)

Pour avoir accegraves agrave notre fenecirctre principale nous ajoutons un champs p_main_window agrave notre structure globaledocs_t que nous initialisons dans la fonction main

mainc docsp_main_window = GTK_WINDOW (p_window)

Il nous reste plus qua creacuteer notre boicircte de dialogue avec trois boutons Oui Non Annuler

callbackc if (docsactif-gtsauve) GtkWidget p_dialog = NULL

p_dialog = gtk_dialog_new_with_buttons (Sauvegarder docsp_main_window GTK_DIALOG_MODAL GTK_STOCK_YES GTK_RESPONSE_YES GTK_STOCK_NO GTK_RESPONSE_NO GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL NULL)

Nous obtenons donc une structure de type GtkDialog

typedef struct GtkWidget vbox GtkWidget action_area GtkDialog

Nous remarquons que cette structure contient deux membres qui permettent dacceacuteder agrave une GtkBox ougrave nous allonsajouter le contenu de la fenecirctre et agrave la partie contenant les boutons

Ensuite la construction de la fenecirctre est identique agrave celle de la fenecirctre principale ici nous nous contenterons dajouterun GtkLabel

callbackc GtkWidget p_label = NULL p_label = gtk_label_new (Voulez-vous sauvegarder les modifications ) gtk_box_pack_start (GTK_BOX (GTK_DIALOG (p_dialog)-gtvbox) p_label TRUE TRUE 0)

Une fois notre fenecirctre precircte il suffit de faire appel agrave la fonction gtk_dialog_run qui va afficher notre GtkDialog et nousretourner le reacuteponse id correspondant au bouton cliqueacute par lutilisateur

callbackc switch (gtk_dialog_run (GTK_DIALOG (p_dialog))) case GTK_RESPONSE_YES cb_save (p_widget user_data) break case GTK_RESPONSE_NO break case GTK_RESPONSE_CANCEL gtk_widget_destroy (p_dialog) return break

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 32 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc gtk_widget_destroy (p_dialog)

Si lutilisateur clique sur non on ne fait rien (le document sera simplement fermeacute) sur oui on enregistre avant defermer et pour finir sil annule on quitte la fonction

X-D - Code source

chapitre10zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 33 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XI - Les barres de deacutefilement

XI-A - Aperccedilu

Cliquez pour agrandir

XI-B - Ajouter des barres de deacutefilement

Apregraves le dernier chapitre quelque peu laborieux voici une partie plus simple mais qui va rendre notre applicationplus pratique En effet si vous avez essayeacute douvrir un fichier de grande taille vous avez pu remarquer que pourpouvoir lire la fin du fichier il fallait utiliser les touches du clavier pas tregraves convivial

Pour rendre la navigation plus aiseacutee on utilise des barres de deacutefilement

mainc GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_scrolled_window TRUE TRUE 0)

Creation de la zone de texte gtk_container_add (GTK_CONTAINER (p_scrolled_window) p_text_view)

Le constructeur de notre GtkScrolledWindow prend en argument deux GtkAdjustment qui permettent de deacutefinirdiffeacuterentes proprieacuteteacutes de la barre de deacutefilement (taille dune page la position de deacutepart) nous laissons GTK+ faireen passant NULL

Cest un bon deacutebut mais estheacutetiquement on peut faire mieux mecircme sil nest pas utile davoir une barre de deacutefilementelle est quand mecircme afficheacutee On peut demander agrave GTK+ de les afficher que si cela est neacutecessaire

mainc gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC)

En fait nous avons de la chance car la classe GtkTextView fait partie des widget qui supporte de faccedilon native les barresde deacutefilement Comment le savoir Ce genre de widget possegravede une ou deux proprieacuteteacutes de type GtkAdjustment (unepour la barre verticale lautre pour la barre horizontale) Actuellement seulement trois classes en sont capables lesGtkTextView les GtkTreeView et les GtkLayout

Comment faire pour les autres widgets Il faut passer par une classe adaptateur GtkViewport afin de creacuteer lesGtkAdjustment

XI-C - Code source

chapitre11zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 34 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XII - Les menus

XII-A - Aperccedilu

Cliquez pour agrandir

XII-B - Creacuteation du menu

Pour simplifier nous avons utiliseacute des boutons pour permettre agrave lutilisateur de creacuteer un document ouvrir un fichierMais il est plus courant dutiliser un menu pour afficher ces options GTK+ propose trois maniegraveres de creacuteer un menu

bull GtkItemFactory cette meacutethode est obsolegravete depuis la version 24 de GTK+

bull GtkUIManager cest ce quon appel une usine agrave gaz pour en savoir plus vous pouvez vous reporter aututoriel Utilisation de GtkUIManager

bull GtkMenu cest ce widget que nous allons eacutetudier il permet de creacuteer un menu manuellement (agrave lopposeacute deGtkUIManager)

Un menu selon GTK+ est composeacute de plusieurs eacuteleacutements

bull GtkMenuBar la barre de menu elle-mecircme

bull GtkMenu la partie deacuteroulante qui contient les diffeacuterents eacuteleacutements

bull GtkMenuItem cest sur ce widget que lutilisateur clique pour lancer une action

Pour commencer faisons linventaire de ce que nous avons besoin

bull Un GtkMenuBar qui sert de base au menu

bull Un GtkMenu pour commencer nous nous aurons dun menu Fichier

bull Six GtkMenuItem pour remplacer nos six boutons

Commenccedilons par la creacuteation du menu nous mettons ce code dans un nouveau fichier dont seul la fonction menu_newsera accessible

menucGtkMenuBar menu_new (gpointer user_data) GtkWidget p_menu_bar = NULL

p_menu_bar = gtk_menu_bar_new () return GTK_MENU_BAR (p_menu_bar)

Le paramegravetre user_data nous servira lors de la connexion des callbacks (nous en avons besoin pour les fonctionscb_new et cb_open)

Ensuite nous allons creacuteer notre sous menu Fichier

menuc Menu Fichier

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 35 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

menuc GtkWidget p_menu = NULL GtkWidget p_menu_item = NULL

p_menu = gtk_menu_new () p_menu_item = gtk_menu_item_new_with_mnemonic (_Fichier) gtk_menu_item_set_submenu (GTK_MENU_ITEM (p_menu_item) p_menu) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu_bar) p_menu_item) return GTK_MENU_BAR (p_menu_bar)

Un sous menu est en fait un GtkMenuItem auquel on assigne un GtkMenu Il faut bien sucircr terminer la creacuteation dusous-menu en lajoutant agrave la barre de menu

Pour finir nous creacuteons les eacuteleacutements du menu les GtkItemMenu Il existe plusieurs types deacuteleacutements (comparableaux diffeacuterents types de bouton) pour commencer nous nutiliserons que le type de base Comme cette opeacuteration estreacutepeacutetitive nous allons creacuteer une fonction pour le faire

menucstatic void menu_item_new (GtkMenu p_menu const gchar title GCallback callback gpointer user_data) GtkWidget p_menu_item = NULL

p_menu_item = gtk_menu_item_new_with_mnemonic (title) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu) p_menu_item) g_signal_connect (G_OBJECT (p_menu_item) activate callback user_data)

Pour permettre agrave lutilisateur dacceacuteder aux diffeacuterents eacuteleacutements du menu agrave laide de la touche ltAltgt nous utilisonsdes mneacutemoniques par exemple pour quitter leacutediteur il suffit de faite Alt+F puis Q Et voici le code pour creacuteer nossix eacuteleacutements du menu

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau G_CALLBACK (cb_new) user_data) menu_item_new (GTK_MENU (p_menu) _Ouvrir G_CALLBACK (cb_open) user_data) menu_item_new (GTK_MENU (p_menu) _Enregistrer G_CALLBACK (cb_save) user_data) menu_item_new (GTK_MENU (p_menu) Enregistrer _sous G_CALLBACK (cb_saveas) user_data) menu_item_new (GTK_MENU (p_menu) _Fermer G_CALLBACK (cb_close) user_data) menu_item_new (GTK_MENU (p_menu) _Quitter G_CALLBACK (cb_quit) user_data)

Voilagrave notre menu est creacuteeacute il nous reste plus quagrave linteacutegrer agrave notre fenecirctre

mainc gtk_box_pack_start (GTK_BOX (p_main_box) GTK_WIDGET (menu_new (p_text_view)) FALSE FALSE 0)

Le problegraveme cest que nous avons besoin de passer le GtkTextView lors de la creacuteation du menu (qui est utiliseacute par lesfonctions cb_new et cb_open) or celui-ci est creacuteeacute apregraves le menu (puisque nous creacuteons les widgets dans lordre ougrave ilfaut les inteacutegrer agrave linterface (8) ) nous devons creacuteer le GtkTextView (seul lappel agrave gtk_text_view_new est deacuteplaceacute)

XII-C - Code source

chapitre12zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 36 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIII - Les barres doutils

XIII-A - Aperccedilu

Cliquez pour agrandir

XIII-B - Creacuteation dune barre doutils

La creacuteation dune barre doutils ressemble fort agrave celle dun menu en plus simple puisquil ny a pas de sous menu on creacutee notre barre doutils (gtk_toolbar_new) puis les eacuteleacutements de la barre pour cela on utilise des boutons(gtk_tool_button_new_from_stock) que lon inseacutere dans la barre (gtk_toolbar_insert) Pas conseacutequent notre fichierbarreoutilsc ressemble agrave menuc

barreoutilscinclude ltgtkgtkhgtinclude callbackhinclude barreoutilsh

static void toolbar_item_new (GtkToolbar const gchar GCallback gpointer)

GtkToolbar toolbar_new (gpointer user_data) GtkWidget p_toolbar = NULL

p_toolbar = gtk_toolbar_new () toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_NEW G_CALLBACK (cb_new) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_OPEN G_CALLBACK (cb_open) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE G_CALLBACK (cb_save) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE_AS G_CALLBACK (cb_saveas) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_CLOSE G_CALLBACK (cb_close) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_QUIT G_CALLBACK (cb_quit) user_data) return GTK_TOOLBAR (p_toolbar)

static void toolbar_item_new (GtkToolbar p_toolbar const gchar stock_id GCallback callback gpointer user_data) GtkToolItem p_tool_item = NULL

p_tool_item = gtk_tool_button_new_from_stock (stock_id) g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data) gtk_toolbar_insert (p_toolbar p_tool_item -1)

Le code nest pas complet car lorsque jexeacutecute le programme GTK+ affiche en plus des icocircnes le texte sous lesboutons Pour modifier cela il suffit dajouter une ligne de code

barreoutilsc gtk_toolbar_set_style (GTK_TOOLBAR (p_toolbar) GTK_TOOLBAR_ICONS)

Pourquoi gtk_tool_button_new_from_stock retourne un GtkToolItem et non un GtkWidgetcomme nous avons eacuteteacute habitueacute jusquagrave preacutesent Il sagit dune bizarrerie de GTK+ dontje ne connais pas la raison

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 37 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour anticiper un changement dinterface (dans GTK+ 30 peut ecirctre ) nous aurions pueacutecrire

Gtkwidget p_tool_item = NULL

p_tool_item = GTK_WIDGET (gtk_tool_button_new_from_stock (stock_id))g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data)gtk_toolbar_insert (p_toolbar GTK_TOOL_ITEM (p_tool_item) -1)

XIII-C - Code source

chapitre13zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 38 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIV - Les racourcis clavier

XIV-A - Aperccedilu

Cliquez pour agrandir

XIV-B - Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mneacutemoniques ces derniers permettent dacceacuteder agrave un eacuteleacutementseacutequentiellement alors que les raccourcis appellent une fonction si lutilisateur appuie simultaneacutement sur une ouplusieurs touches (geacuteneacuteralement de la forme ltModificateurgtTouche ougrave Modificateur repreacutesente les touches ShiftAlt et Control) Ce raccourci peut ecirctre attacheacute agrave un eacuteleacutement du menu mais ceci nest pas obligatoire

Les raccourcis sont regroupeacutes en groupe dans un GtkAccelGroup quil faut commencer par creacuteer

raccourciscinclude ltgtkgtkhgtinclude callbackhinclude raccourcish

GtkAccelGroup accel_group_new (gpointer user_data) GtkAccelGroup p_accel_group = NULL

p_accel_group = gtk_accel_group_new () return p_accel_group

Vous commencez agrave avoir lhabitude de cette organisation nous allons donc creacuteer une fonction qui va se chargerdajouter un raccourci au groupe

raccourciscstatic void accelerator_new (GtkAccelGroup p_accel_group const gchar accelerator const gchar accel_path GCallback callback gpointer user_data) guint key GdkModifierType mods GClosure closure = NULL

gtk_accelerator_parse (accelerator ampkey ampmods) closure = g_cclosure_new (callback user_data NULL) gtk_accel_group_connect (p_accel_group key mods GTK_ACCEL_VISIBLE closure) gtk_accel_map_add_entry (accel_path key mods)

La fonction gtk_accelerator_parse permet de deacutecomposer une chaicircne de caractegraveres de la forme ltControlgtF1 ouencore ltAltgtA en numeacutero de touche et modificateur

En plus des touches pour creacuteer un raccourci clavier nous avons besoin dune fonction agrave appeler lorsque lutilisateurappuie sur les touches speacutecifieacutees gtk_accel_group_connect attend une fonction du type GClosure regardons ladocumentation de gobject pour savoir agrave quoi cela correspond

typedef struct

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 27 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

IX - Creacuteer un nouveau document

IX-A - Aperccedilu

Cliquez pour agrandir

IX-B - Nouveau fichier

Maintenant que lutilisateur peut ouvrir et fermer un fichier il est inteacuteressant de lui donner la possibiliteacute den creacuteerun nouveau Je ne reviens pas sur la creacuteation du bouton (ccedila devrait deacutejagrave ecirctre fait D) passons directement agrave lafonction cb_new

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) Pour linstant il faut allouer la memoire par la suite on modifiera simplement le pointeur docsactif = g_malloc (sizeof (docsactif)) docsactif-gtchemin = NULL Pour linstant on se contente de stocker le seul GtkTextView qui existe par la suite il faudra en creer un nouveau docsactif-gtp_text_view = GTK_TEXT_VIEW (user_data) Le document vient detre creer il nest donc pas modifie docsactif-gtsauve = TRUE gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Je ne sais pas vous mais pour ma part jai fait un copiercoller de la fonction open_file Et oui ouvrir un document peutse reacutesumer agrave creacuteer un document vide puis remplir le GtkTextView avec le fichier souhaiteacute On peut donc simplifiernotre fonction open_file ainsi

callbackcstatic void open_file (const gchar file_name GtkTextView p_text_view) g_return_if_fail (file_name ampamp p_text_view) gchar contents = NULL

if (g_file_get_contents (file_name ampcontents NULL NULL)) Copie de contents dans le GtkTextView GtkTextIter iter GtkTextBuffer p_text_buffer = NULL

cb_new (NULL p_text_view) gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE) p_text_buffer = gtk_text_view_get_buffer (p_text_view) gtk_text_buffer_get_iter_at_line (p_text_buffer ampiter 0) gtk_text_buffer_insert (p_text_buffer ampiter contents -1) Nous sommes obliges de remetre sauve a TRUE car linsertion du contenu du fichier dans le GtkTextView a appele cb_modfie docsactif-gtsauve = TRUE else print_warning (Impossible douvrir le fichier sn file_name)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 28 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc

Cest beau la factorisation du code Par contre nous sommes obligeacutes de remettre sauve agrave TRUE car nous avonsmodifieacute le GtkTextBuffer

IX-C - Code source

chapitre9zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 29 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

X - Fermer

X-A - Aperccedilu

Cliquez pour agrandir

X-B - Fermer un fichier

Maintenant que nous allouons de la meacutemoire il faut la libeacuterer agrave un endroit Logiquement cela va ecirctre fait agrave la fermeturedu document en guise dexercice je vous laisse creacuteer le bouton dans notre boicircte agrave bouton

Allez je vous aide le stock id correspondant est GTK_STOCK_CLOSE

Voilagrave maintenant si tout cest bien passeacute vous devriez ecirctre arriveacute dans le fichier callbackc avec quelque choseressemblant agrave

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data)

Lorsque lon ferme un document il faut vider le GtkTextView (avec les onglets on se contentera de le supprimer)pour cela il faut reacutecupeacuterer le deacutebut et la fin du GtkTextBuffer et demander agrave GTK+ de supprimer tout ce qui ce trouveentre les deux iteacuterateurs

callbackc Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) gtk_text_buffer_delete (p_text_buffer ampstart ampend) else print_warning (Aucun document ouvert)

Bien sucircr il ne faut pas oublier de libeacuterer la meacutemoire

callbackc g_free (docsactif-gtchemin) docsactif-gtchemin = NULL docsactif-gtp_text_view = NULL g_free (docsactif) docsactif = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 30 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour symboliser la fermeture dun document nous deacutesactivons le GtkTextView lors de la fermeture (ne pas oublierde le faire aussi dans mainc)

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) FALSE)

Et nous le reacuteactivons lors de louverture si celle si reacuteussie

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Lorsque lutilisateur quitte lapplication il faut bien sucircr fermer le document sil y en a un ouvert

void cb_quit (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data) gtk_main_quit()

Et aussi lorsquil creacuteeacute un nouveau document (et par conseacutequent lorsquil ouvre un fichier puisque lon fait appel agravecb_new)

void cb_new (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data)

X-C - Enregistrer avant de fermer

Si le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde geacuteneacuteralement le programme le signale agrave lutilisateur etlui propose de sauvegarder ou dannuler la fermeture Pour se faire nous devons modifier la fonction cb_close avantde fermer le document nous allons afficher une boicircte de dialogue

Pour creacuteer une boicircte de dialogue simplement il existe la classe GtkDialog et comme nous avons besoin de boutons(pour que lutilisateur fasse son choix) nous allons creacuteer notre boicircte avec la fonction

GtkWidget gtk_dialog_new_with_buttons (const gchar title GtkWindow parent GtkDialogFlags flags const gchar first_button_text )

Nous retrouvons les mecircmes options que pour le GtkFileChooserDialog mis agrave part option du type GtkDialogFlags

typedef enum GTK_DIALOG_MODAL = 1 ltlt 0 appel gtk_window_set_modal (win TRUE) GTK_DIALOG_DESTROY_WITH_PARENT = 1 ltlt 1 appel gtk_window_set_destroy_with_parent () GTK_DIALOG_NO_SEPARATOR = 1 ltlt 2 Pas de barre de separation au dessus des boutons GtkDialogFlags

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 31 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Nous nous contenterons de rendre notre fenecirctre modale (7)

Pour avoir accegraves agrave notre fenecirctre principale nous ajoutons un champs p_main_window agrave notre structure globaledocs_t que nous initialisons dans la fonction main

mainc docsp_main_window = GTK_WINDOW (p_window)

Il nous reste plus qua creacuteer notre boicircte de dialogue avec trois boutons Oui Non Annuler

callbackc if (docsactif-gtsauve) GtkWidget p_dialog = NULL

p_dialog = gtk_dialog_new_with_buttons (Sauvegarder docsp_main_window GTK_DIALOG_MODAL GTK_STOCK_YES GTK_RESPONSE_YES GTK_STOCK_NO GTK_RESPONSE_NO GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL NULL)

Nous obtenons donc une structure de type GtkDialog

typedef struct GtkWidget vbox GtkWidget action_area GtkDialog

Nous remarquons que cette structure contient deux membres qui permettent dacceacuteder agrave une GtkBox ougrave nous allonsajouter le contenu de la fenecirctre et agrave la partie contenant les boutons

Ensuite la construction de la fenecirctre est identique agrave celle de la fenecirctre principale ici nous nous contenterons dajouterun GtkLabel

callbackc GtkWidget p_label = NULL p_label = gtk_label_new (Voulez-vous sauvegarder les modifications ) gtk_box_pack_start (GTK_BOX (GTK_DIALOG (p_dialog)-gtvbox) p_label TRUE TRUE 0)

Une fois notre fenecirctre precircte il suffit de faire appel agrave la fonction gtk_dialog_run qui va afficher notre GtkDialog et nousretourner le reacuteponse id correspondant au bouton cliqueacute par lutilisateur

callbackc switch (gtk_dialog_run (GTK_DIALOG (p_dialog))) case GTK_RESPONSE_YES cb_save (p_widget user_data) break case GTK_RESPONSE_NO break case GTK_RESPONSE_CANCEL gtk_widget_destroy (p_dialog) return break

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 32 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc gtk_widget_destroy (p_dialog)

Si lutilisateur clique sur non on ne fait rien (le document sera simplement fermeacute) sur oui on enregistre avant defermer et pour finir sil annule on quitte la fonction

X-D - Code source

chapitre10zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 33 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XI - Les barres de deacutefilement

XI-A - Aperccedilu

Cliquez pour agrandir

XI-B - Ajouter des barres de deacutefilement

Apregraves le dernier chapitre quelque peu laborieux voici une partie plus simple mais qui va rendre notre applicationplus pratique En effet si vous avez essayeacute douvrir un fichier de grande taille vous avez pu remarquer que pourpouvoir lire la fin du fichier il fallait utiliser les touches du clavier pas tregraves convivial

Pour rendre la navigation plus aiseacutee on utilise des barres de deacutefilement

mainc GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_scrolled_window TRUE TRUE 0)

Creation de la zone de texte gtk_container_add (GTK_CONTAINER (p_scrolled_window) p_text_view)

Le constructeur de notre GtkScrolledWindow prend en argument deux GtkAdjustment qui permettent de deacutefinirdiffeacuterentes proprieacuteteacutes de la barre de deacutefilement (taille dune page la position de deacutepart) nous laissons GTK+ faireen passant NULL

Cest un bon deacutebut mais estheacutetiquement on peut faire mieux mecircme sil nest pas utile davoir une barre de deacutefilementelle est quand mecircme afficheacutee On peut demander agrave GTK+ de les afficher que si cela est neacutecessaire

mainc gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC)

En fait nous avons de la chance car la classe GtkTextView fait partie des widget qui supporte de faccedilon native les barresde deacutefilement Comment le savoir Ce genre de widget possegravede une ou deux proprieacuteteacutes de type GtkAdjustment (unepour la barre verticale lautre pour la barre horizontale) Actuellement seulement trois classes en sont capables lesGtkTextView les GtkTreeView et les GtkLayout

Comment faire pour les autres widgets Il faut passer par une classe adaptateur GtkViewport afin de creacuteer lesGtkAdjustment

XI-C - Code source

chapitre11zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 34 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XII - Les menus

XII-A - Aperccedilu

Cliquez pour agrandir

XII-B - Creacuteation du menu

Pour simplifier nous avons utiliseacute des boutons pour permettre agrave lutilisateur de creacuteer un document ouvrir un fichierMais il est plus courant dutiliser un menu pour afficher ces options GTK+ propose trois maniegraveres de creacuteer un menu

bull GtkItemFactory cette meacutethode est obsolegravete depuis la version 24 de GTK+

bull GtkUIManager cest ce quon appel une usine agrave gaz pour en savoir plus vous pouvez vous reporter aututoriel Utilisation de GtkUIManager

bull GtkMenu cest ce widget que nous allons eacutetudier il permet de creacuteer un menu manuellement (agrave lopposeacute deGtkUIManager)

Un menu selon GTK+ est composeacute de plusieurs eacuteleacutements

bull GtkMenuBar la barre de menu elle-mecircme

bull GtkMenu la partie deacuteroulante qui contient les diffeacuterents eacuteleacutements

bull GtkMenuItem cest sur ce widget que lutilisateur clique pour lancer une action

Pour commencer faisons linventaire de ce que nous avons besoin

bull Un GtkMenuBar qui sert de base au menu

bull Un GtkMenu pour commencer nous nous aurons dun menu Fichier

bull Six GtkMenuItem pour remplacer nos six boutons

Commenccedilons par la creacuteation du menu nous mettons ce code dans un nouveau fichier dont seul la fonction menu_newsera accessible

menucGtkMenuBar menu_new (gpointer user_data) GtkWidget p_menu_bar = NULL

p_menu_bar = gtk_menu_bar_new () return GTK_MENU_BAR (p_menu_bar)

Le paramegravetre user_data nous servira lors de la connexion des callbacks (nous en avons besoin pour les fonctionscb_new et cb_open)

Ensuite nous allons creacuteer notre sous menu Fichier

menuc Menu Fichier

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 35 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

menuc GtkWidget p_menu = NULL GtkWidget p_menu_item = NULL

p_menu = gtk_menu_new () p_menu_item = gtk_menu_item_new_with_mnemonic (_Fichier) gtk_menu_item_set_submenu (GTK_MENU_ITEM (p_menu_item) p_menu) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu_bar) p_menu_item) return GTK_MENU_BAR (p_menu_bar)

Un sous menu est en fait un GtkMenuItem auquel on assigne un GtkMenu Il faut bien sucircr terminer la creacuteation dusous-menu en lajoutant agrave la barre de menu

Pour finir nous creacuteons les eacuteleacutements du menu les GtkItemMenu Il existe plusieurs types deacuteleacutements (comparableaux diffeacuterents types de bouton) pour commencer nous nutiliserons que le type de base Comme cette opeacuteration estreacutepeacutetitive nous allons creacuteer une fonction pour le faire

menucstatic void menu_item_new (GtkMenu p_menu const gchar title GCallback callback gpointer user_data) GtkWidget p_menu_item = NULL

p_menu_item = gtk_menu_item_new_with_mnemonic (title) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu) p_menu_item) g_signal_connect (G_OBJECT (p_menu_item) activate callback user_data)

Pour permettre agrave lutilisateur dacceacuteder aux diffeacuterents eacuteleacutements du menu agrave laide de la touche ltAltgt nous utilisonsdes mneacutemoniques par exemple pour quitter leacutediteur il suffit de faite Alt+F puis Q Et voici le code pour creacuteer nossix eacuteleacutements du menu

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau G_CALLBACK (cb_new) user_data) menu_item_new (GTK_MENU (p_menu) _Ouvrir G_CALLBACK (cb_open) user_data) menu_item_new (GTK_MENU (p_menu) _Enregistrer G_CALLBACK (cb_save) user_data) menu_item_new (GTK_MENU (p_menu) Enregistrer _sous G_CALLBACK (cb_saveas) user_data) menu_item_new (GTK_MENU (p_menu) _Fermer G_CALLBACK (cb_close) user_data) menu_item_new (GTK_MENU (p_menu) _Quitter G_CALLBACK (cb_quit) user_data)

Voilagrave notre menu est creacuteeacute il nous reste plus quagrave linteacutegrer agrave notre fenecirctre

mainc gtk_box_pack_start (GTK_BOX (p_main_box) GTK_WIDGET (menu_new (p_text_view)) FALSE FALSE 0)

Le problegraveme cest que nous avons besoin de passer le GtkTextView lors de la creacuteation du menu (qui est utiliseacute par lesfonctions cb_new et cb_open) or celui-ci est creacuteeacute apregraves le menu (puisque nous creacuteons les widgets dans lordre ougrave ilfaut les inteacutegrer agrave linterface (8) ) nous devons creacuteer le GtkTextView (seul lappel agrave gtk_text_view_new est deacuteplaceacute)

XII-C - Code source

chapitre12zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 36 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIII - Les barres doutils

XIII-A - Aperccedilu

Cliquez pour agrandir

XIII-B - Creacuteation dune barre doutils

La creacuteation dune barre doutils ressemble fort agrave celle dun menu en plus simple puisquil ny a pas de sous menu on creacutee notre barre doutils (gtk_toolbar_new) puis les eacuteleacutements de la barre pour cela on utilise des boutons(gtk_tool_button_new_from_stock) que lon inseacutere dans la barre (gtk_toolbar_insert) Pas conseacutequent notre fichierbarreoutilsc ressemble agrave menuc

barreoutilscinclude ltgtkgtkhgtinclude callbackhinclude barreoutilsh

static void toolbar_item_new (GtkToolbar const gchar GCallback gpointer)

GtkToolbar toolbar_new (gpointer user_data) GtkWidget p_toolbar = NULL

p_toolbar = gtk_toolbar_new () toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_NEW G_CALLBACK (cb_new) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_OPEN G_CALLBACK (cb_open) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE G_CALLBACK (cb_save) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE_AS G_CALLBACK (cb_saveas) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_CLOSE G_CALLBACK (cb_close) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_QUIT G_CALLBACK (cb_quit) user_data) return GTK_TOOLBAR (p_toolbar)

static void toolbar_item_new (GtkToolbar p_toolbar const gchar stock_id GCallback callback gpointer user_data) GtkToolItem p_tool_item = NULL

p_tool_item = gtk_tool_button_new_from_stock (stock_id) g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data) gtk_toolbar_insert (p_toolbar p_tool_item -1)

Le code nest pas complet car lorsque jexeacutecute le programme GTK+ affiche en plus des icocircnes le texte sous lesboutons Pour modifier cela il suffit dajouter une ligne de code

barreoutilsc gtk_toolbar_set_style (GTK_TOOLBAR (p_toolbar) GTK_TOOLBAR_ICONS)

Pourquoi gtk_tool_button_new_from_stock retourne un GtkToolItem et non un GtkWidgetcomme nous avons eacuteteacute habitueacute jusquagrave preacutesent Il sagit dune bizarrerie de GTK+ dontje ne connais pas la raison

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 37 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour anticiper un changement dinterface (dans GTK+ 30 peut ecirctre ) nous aurions pueacutecrire

Gtkwidget p_tool_item = NULL

p_tool_item = GTK_WIDGET (gtk_tool_button_new_from_stock (stock_id))g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data)gtk_toolbar_insert (p_toolbar GTK_TOOL_ITEM (p_tool_item) -1)

XIII-C - Code source

chapitre13zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 38 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIV - Les racourcis clavier

XIV-A - Aperccedilu

Cliquez pour agrandir

XIV-B - Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mneacutemoniques ces derniers permettent dacceacuteder agrave un eacuteleacutementseacutequentiellement alors que les raccourcis appellent une fonction si lutilisateur appuie simultaneacutement sur une ouplusieurs touches (geacuteneacuteralement de la forme ltModificateurgtTouche ougrave Modificateur repreacutesente les touches ShiftAlt et Control) Ce raccourci peut ecirctre attacheacute agrave un eacuteleacutement du menu mais ceci nest pas obligatoire

Les raccourcis sont regroupeacutes en groupe dans un GtkAccelGroup quil faut commencer par creacuteer

raccourciscinclude ltgtkgtkhgtinclude callbackhinclude raccourcish

GtkAccelGroup accel_group_new (gpointer user_data) GtkAccelGroup p_accel_group = NULL

p_accel_group = gtk_accel_group_new () return p_accel_group

Vous commencez agrave avoir lhabitude de cette organisation nous allons donc creacuteer une fonction qui va se chargerdajouter un raccourci au groupe

raccourciscstatic void accelerator_new (GtkAccelGroup p_accel_group const gchar accelerator const gchar accel_path GCallback callback gpointer user_data) guint key GdkModifierType mods GClosure closure = NULL

gtk_accelerator_parse (accelerator ampkey ampmods) closure = g_cclosure_new (callback user_data NULL) gtk_accel_group_connect (p_accel_group key mods GTK_ACCEL_VISIBLE closure) gtk_accel_map_add_entry (accel_path key mods)

La fonction gtk_accelerator_parse permet de deacutecomposer une chaicircne de caractegraveres de la forme ltControlgtF1 ouencore ltAltgtA en numeacutero de touche et modificateur

En plus des touches pour creacuteer un raccourci clavier nous avons besoin dune fonction agrave appeler lorsque lutilisateurappuie sur les touches speacutecifieacutees gtk_accel_group_connect attend une fonction du type GClosure regardons ladocumentation de gobject pour savoir agrave quoi cela correspond

typedef struct

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 28 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc

Cest beau la factorisation du code Par contre nous sommes obligeacutes de remettre sauve agrave TRUE car nous avonsmodifieacute le GtkTextBuffer

IX-C - Code source

chapitre9zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 29 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

X - Fermer

X-A - Aperccedilu

Cliquez pour agrandir

X-B - Fermer un fichier

Maintenant que nous allouons de la meacutemoire il faut la libeacuterer agrave un endroit Logiquement cela va ecirctre fait agrave la fermeturedu document en guise dexercice je vous laisse creacuteer le bouton dans notre boicircte agrave bouton

Allez je vous aide le stock id correspondant est GTK_STOCK_CLOSE

Voilagrave maintenant si tout cest bien passeacute vous devriez ecirctre arriveacute dans le fichier callbackc avec quelque choseressemblant agrave

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data)

Lorsque lon ferme un document il faut vider le GtkTextView (avec les onglets on se contentera de le supprimer)pour cela il faut reacutecupeacuterer le deacutebut et la fin du GtkTextBuffer et demander agrave GTK+ de supprimer tout ce qui ce trouveentre les deux iteacuterateurs

callbackc Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) gtk_text_buffer_delete (p_text_buffer ampstart ampend) else print_warning (Aucun document ouvert)

Bien sucircr il ne faut pas oublier de libeacuterer la meacutemoire

callbackc g_free (docsactif-gtchemin) docsactif-gtchemin = NULL docsactif-gtp_text_view = NULL g_free (docsactif) docsactif = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 30 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour symboliser la fermeture dun document nous deacutesactivons le GtkTextView lors de la fermeture (ne pas oublierde le faire aussi dans mainc)

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) FALSE)

Et nous le reacuteactivons lors de louverture si celle si reacuteussie

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Lorsque lutilisateur quitte lapplication il faut bien sucircr fermer le document sil y en a un ouvert

void cb_quit (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data) gtk_main_quit()

Et aussi lorsquil creacuteeacute un nouveau document (et par conseacutequent lorsquil ouvre un fichier puisque lon fait appel agravecb_new)

void cb_new (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data)

X-C - Enregistrer avant de fermer

Si le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde geacuteneacuteralement le programme le signale agrave lutilisateur etlui propose de sauvegarder ou dannuler la fermeture Pour se faire nous devons modifier la fonction cb_close avantde fermer le document nous allons afficher une boicircte de dialogue

Pour creacuteer une boicircte de dialogue simplement il existe la classe GtkDialog et comme nous avons besoin de boutons(pour que lutilisateur fasse son choix) nous allons creacuteer notre boicircte avec la fonction

GtkWidget gtk_dialog_new_with_buttons (const gchar title GtkWindow parent GtkDialogFlags flags const gchar first_button_text )

Nous retrouvons les mecircmes options que pour le GtkFileChooserDialog mis agrave part option du type GtkDialogFlags

typedef enum GTK_DIALOG_MODAL = 1 ltlt 0 appel gtk_window_set_modal (win TRUE) GTK_DIALOG_DESTROY_WITH_PARENT = 1 ltlt 1 appel gtk_window_set_destroy_with_parent () GTK_DIALOG_NO_SEPARATOR = 1 ltlt 2 Pas de barre de separation au dessus des boutons GtkDialogFlags

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 31 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Nous nous contenterons de rendre notre fenecirctre modale (7)

Pour avoir accegraves agrave notre fenecirctre principale nous ajoutons un champs p_main_window agrave notre structure globaledocs_t que nous initialisons dans la fonction main

mainc docsp_main_window = GTK_WINDOW (p_window)

Il nous reste plus qua creacuteer notre boicircte de dialogue avec trois boutons Oui Non Annuler

callbackc if (docsactif-gtsauve) GtkWidget p_dialog = NULL

p_dialog = gtk_dialog_new_with_buttons (Sauvegarder docsp_main_window GTK_DIALOG_MODAL GTK_STOCK_YES GTK_RESPONSE_YES GTK_STOCK_NO GTK_RESPONSE_NO GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL NULL)

Nous obtenons donc une structure de type GtkDialog

typedef struct GtkWidget vbox GtkWidget action_area GtkDialog

Nous remarquons que cette structure contient deux membres qui permettent dacceacuteder agrave une GtkBox ougrave nous allonsajouter le contenu de la fenecirctre et agrave la partie contenant les boutons

Ensuite la construction de la fenecirctre est identique agrave celle de la fenecirctre principale ici nous nous contenterons dajouterun GtkLabel

callbackc GtkWidget p_label = NULL p_label = gtk_label_new (Voulez-vous sauvegarder les modifications ) gtk_box_pack_start (GTK_BOX (GTK_DIALOG (p_dialog)-gtvbox) p_label TRUE TRUE 0)

Une fois notre fenecirctre precircte il suffit de faire appel agrave la fonction gtk_dialog_run qui va afficher notre GtkDialog et nousretourner le reacuteponse id correspondant au bouton cliqueacute par lutilisateur

callbackc switch (gtk_dialog_run (GTK_DIALOG (p_dialog))) case GTK_RESPONSE_YES cb_save (p_widget user_data) break case GTK_RESPONSE_NO break case GTK_RESPONSE_CANCEL gtk_widget_destroy (p_dialog) return break

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 32 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc gtk_widget_destroy (p_dialog)

Si lutilisateur clique sur non on ne fait rien (le document sera simplement fermeacute) sur oui on enregistre avant defermer et pour finir sil annule on quitte la fonction

X-D - Code source

chapitre10zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 33 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XI - Les barres de deacutefilement

XI-A - Aperccedilu

Cliquez pour agrandir

XI-B - Ajouter des barres de deacutefilement

Apregraves le dernier chapitre quelque peu laborieux voici une partie plus simple mais qui va rendre notre applicationplus pratique En effet si vous avez essayeacute douvrir un fichier de grande taille vous avez pu remarquer que pourpouvoir lire la fin du fichier il fallait utiliser les touches du clavier pas tregraves convivial

Pour rendre la navigation plus aiseacutee on utilise des barres de deacutefilement

mainc GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_scrolled_window TRUE TRUE 0)

Creation de la zone de texte gtk_container_add (GTK_CONTAINER (p_scrolled_window) p_text_view)

Le constructeur de notre GtkScrolledWindow prend en argument deux GtkAdjustment qui permettent de deacutefinirdiffeacuterentes proprieacuteteacutes de la barre de deacutefilement (taille dune page la position de deacutepart) nous laissons GTK+ faireen passant NULL

Cest un bon deacutebut mais estheacutetiquement on peut faire mieux mecircme sil nest pas utile davoir une barre de deacutefilementelle est quand mecircme afficheacutee On peut demander agrave GTK+ de les afficher que si cela est neacutecessaire

mainc gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC)

En fait nous avons de la chance car la classe GtkTextView fait partie des widget qui supporte de faccedilon native les barresde deacutefilement Comment le savoir Ce genre de widget possegravede une ou deux proprieacuteteacutes de type GtkAdjustment (unepour la barre verticale lautre pour la barre horizontale) Actuellement seulement trois classes en sont capables lesGtkTextView les GtkTreeView et les GtkLayout

Comment faire pour les autres widgets Il faut passer par une classe adaptateur GtkViewport afin de creacuteer lesGtkAdjustment

XI-C - Code source

chapitre11zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 34 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XII - Les menus

XII-A - Aperccedilu

Cliquez pour agrandir

XII-B - Creacuteation du menu

Pour simplifier nous avons utiliseacute des boutons pour permettre agrave lutilisateur de creacuteer un document ouvrir un fichierMais il est plus courant dutiliser un menu pour afficher ces options GTK+ propose trois maniegraveres de creacuteer un menu

bull GtkItemFactory cette meacutethode est obsolegravete depuis la version 24 de GTK+

bull GtkUIManager cest ce quon appel une usine agrave gaz pour en savoir plus vous pouvez vous reporter aututoriel Utilisation de GtkUIManager

bull GtkMenu cest ce widget que nous allons eacutetudier il permet de creacuteer un menu manuellement (agrave lopposeacute deGtkUIManager)

Un menu selon GTK+ est composeacute de plusieurs eacuteleacutements

bull GtkMenuBar la barre de menu elle-mecircme

bull GtkMenu la partie deacuteroulante qui contient les diffeacuterents eacuteleacutements

bull GtkMenuItem cest sur ce widget que lutilisateur clique pour lancer une action

Pour commencer faisons linventaire de ce que nous avons besoin

bull Un GtkMenuBar qui sert de base au menu

bull Un GtkMenu pour commencer nous nous aurons dun menu Fichier

bull Six GtkMenuItem pour remplacer nos six boutons

Commenccedilons par la creacuteation du menu nous mettons ce code dans un nouveau fichier dont seul la fonction menu_newsera accessible

menucGtkMenuBar menu_new (gpointer user_data) GtkWidget p_menu_bar = NULL

p_menu_bar = gtk_menu_bar_new () return GTK_MENU_BAR (p_menu_bar)

Le paramegravetre user_data nous servira lors de la connexion des callbacks (nous en avons besoin pour les fonctionscb_new et cb_open)

Ensuite nous allons creacuteer notre sous menu Fichier

menuc Menu Fichier

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 35 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

menuc GtkWidget p_menu = NULL GtkWidget p_menu_item = NULL

p_menu = gtk_menu_new () p_menu_item = gtk_menu_item_new_with_mnemonic (_Fichier) gtk_menu_item_set_submenu (GTK_MENU_ITEM (p_menu_item) p_menu) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu_bar) p_menu_item) return GTK_MENU_BAR (p_menu_bar)

Un sous menu est en fait un GtkMenuItem auquel on assigne un GtkMenu Il faut bien sucircr terminer la creacuteation dusous-menu en lajoutant agrave la barre de menu

Pour finir nous creacuteons les eacuteleacutements du menu les GtkItemMenu Il existe plusieurs types deacuteleacutements (comparableaux diffeacuterents types de bouton) pour commencer nous nutiliserons que le type de base Comme cette opeacuteration estreacutepeacutetitive nous allons creacuteer une fonction pour le faire

menucstatic void menu_item_new (GtkMenu p_menu const gchar title GCallback callback gpointer user_data) GtkWidget p_menu_item = NULL

p_menu_item = gtk_menu_item_new_with_mnemonic (title) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu) p_menu_item) g_signal_connect (G_OBJECT (p_menu_item) activate callback user_data)

Pour permettre agrave lutilisateur dacceacuteder aux diffeacuterents eacuteleacutements du menu agrave laide de la touche ltAltgt nous utilisonsdes mneacutemoniques par exemple pour quitter leacutediteur il suffit de faite Alt+F puis Q Et voici le code pour creacuteer nossix eacuteleacutements du menu

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau G_CALLBACK (cb_new) user_data) menu_item_new (GTK_MENU (p_menu) _Ouvrir G_CALLBACK (cb_open) user_data) menu_item_new (GTK_MENU (p_menu) _Enregistrer G_CALLBACK (cb_save) user_data) menu_item_new (GTK_MENU (p_menu) Enregistrer _sous G_CALLBACK (cb_saveas) user_data) menu_item_new (GTK_MENU (p_menu) _Fermer G_CALLBACK (cb_close) user_data) menu_item_new (GTK_MENU (p_menu) _Quitter G_CALLBACK (cb_quit) user_data)

Voilagrave notre menu est creacuteeacute il nous reste plus quagrave linteacutegrer agrave notre fenecirctre

mainc gtk_box_pack_start (GTK_BOX (p_main_box) GTK_WIDGET (menu_new (p_text_view)) FALSE FALSE 0)

Le problegraveme cest que nous avons besoin de passer le GtkTextView lors de la creacuteation du menu (qui est utiliseacute par lesfonctions cb_new et cb_open) or celui-ci est creacuteeacute apregraves le menu (puisque nous creacuteons les widgets dans lordre ougrave ilfaut les inteacutegrer agrave linterface (8) ) nous devons creacuteer le GtkTextView (seul lappel agrave gtk_text_view_new est deacuteplaceacute)

XII-C - Code source

chapitre12zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 36 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIII - Les barres doutils

XIII-A - Aperccedilu

Cliquez pour agrandir

XIII-B - Creacuteation dune barre doutils

La creacuteation dune barre doutils ressemble fort agrave celle dun menu en plus simple puisquil ny a pas de sous menu on creacutee notre barre doutils (gtk_toolbar_new) puis les eacuteleacutements de la barre pour cela on utilise des boutons(gtk_tool_button_new_from_stock) que lon inseacutere dans la barre (gtk_toolbar_insert) Pas conseacutequent notre fichierbarreoutilsc ressemble agrave menuc

barreoutilscinclude ltgtkgtkhgtinclude callbackhinclude barreoutilsh

static void toolbar_item_new (GtkToolbar const gchar GCallback gpointer)

GtkToolbar toolbar_new (gpointer user_data) GtkWidget p_toolbar = NULL

p_toolbar = gtk_toolbar_new () toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_NEW G_CALLBACK (cb_new) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_OPEN G_CALLBACK (cb_open) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE G_CALLBACK (cb_save) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE_AS G_CALLBACK (cb_saveas) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_CLOSE G_CALLBACK (cb_close) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_QUIT G_CALLBACK (cb_quit) user_data) return GTK_TOOLBAR (p_toolbar)

static void toolbar_item_new (GtkToolbar p_toolbar const gchar stock_id GCallback callback gpointer user_data) GtkToolItem p_tool_item = NULL

p_tool_item = gtk_tool_button_new_from_stock (stock_id) g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data) gtk_toolbar_insert (p_toolbar p_tool_item -1)

Le code nest pas complet car lorsque jexeacutecute le programme GTK+ affiche en plus des icocircnes le texte sous lesboutons Pour modifier cela il suffit dajouter une ligne de code

barreoutilsc gtk_toolbar_set_style (GTK_TOOLBAR (p_toolbar) GTK_TOOLBAR_ICONS)

Pourquoi gtk_tool_button_new_from_stock retourne un GtkToolItem et non un GtkWidgetcomme nous avons eacuteteacute habitueacute jusquagrave preacutesent Il sagit dune bizarrerie de GTK+ dontje ne connais pas la raison

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 37 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour anticiper un changement dinterface (dans GTK+ 30 peut ecirctre ) nous aurions pueacutecrire

Gtkwidget p_tool_item = NULL

p_tool_item = GTK_WIDGET (gtk_tool_button_new_from_stock (stock_id))g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data)gtk_toolbar_insert (p_toolbar GTK_TOOL_ITEM (p_tool_item) -1)

XIII-C - Code source

chapitre13zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 38 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIV - Les racourcis clavier

XIV-A - Aperccedilu

Cliquez pour agrandir

XIV-B - Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mneacutemoniques ces derniers permettent dacceacuteder agrave un eacuteleacutementseacutequentiellement alors que les raccourcis appellent une fonction si lutilisateur appuie simultaneacutement sur une ouplusieurs touches (geacuteneacuteralement de la forme ltModificateurgtTouche ougrave Modificateur repreacutesente les touches ShiftAlt et Control) Ce raccourci peut ecirctre attacheacute agrave un eacuteleacutement du menu mais ceci nest pas obligatoire

Les raccourcis sont regroupeacutes en groupe dans un GtkAccelGroup quil faut commencer par creacuteer

raccourciscinclude ltgtkgtkhgtinclude callbackhinclude raccourcish

GtkAccelGroup accel_group_new (gpointer user_data) GtkAccelGroup p_accel_group = NULL

p_accel_group = gtk_accel_group_new () return p_accel_group

Vous commencez agrave avoir lhabitude de cette organisation nous allons donc creacuteer une fonction qui va se chargerdajouter un raccourci au groupe

raccourciscstatic void accelerator_new (GtkAccelGroup p_accel_group const gchar accelerator const gchar accel_path GCallback callback gpointer user_data) guint key GdkModifierType mods GClosure closure = NULL

gtk_accelerator_parse (accelerator ampkey ampmods) closure = g_cclosure_new (callback user_data NULL) gtk_accel_group_connect (p_accel_group key mods GTK_ACCEL_VISIBLE closure) gtk_accel_map_add_entry (accel_path key mods)

La fonction gtk_accelerator_parse permet de deacutecomposer une chaicircne de caractegraveres de la forme ltControlgtF1 ouencore ltAltgtA en numeacutero de touche et modificateur

En plus des touches pour creacuteer un raccourci clavier nous avons besoin dune fonction agrave appeler lorsque lutilisateurappuie sur les touches speacutecifieacutees gtk_accel_group_connect attend une fonction du type GClosure regardons ladocumentation de gobject pour savoir agrave quoi cela correspond

typedef struct

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 29 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

X - Fermer

X-A - Aperccedilu

Cliquez pour agrandir

X-B - Fermer un fichier

Maintenant que nous allouons de la meacutemoire il faut la libeacuterer agrave un endroit Logiquement cela va ecirctre fait agrave la fermeturedu document en guise dexercice je vous laisse creacuteer le bouton dans notre boicircte agrave bouton

Allez je vous aide le stock id correspondant est GTK_STOCK_CLOSE

Voilagrave maintenant si tout cest bien passeacute vous devriez ecirctre arriveacute dans le fichier callbackc avec quelque choseressemblant agrave

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data)

Lorsque lon ferme un document il faut vider le GtkTextView (avec les onglets on se contentera de le supprimer)pour cela il faut reacutecupeacuterer le deacutebut et la fin du GtkTextBuffer et demander agrave GTK+ de supprimer tout ce qui ce trouveentre les deux iteacuterateurs

callbackc Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) GtkTextIter start GtkTextIter end GtkTextBuffer p_text_buffer = NULL

p_text_buffer = gtk_text_view_get_buffer (docsactif-gtp_text_view) gtk_text_buffer_get_bounds (p_text_buffer ampstart ampend) gtk_text_buffer_delete (p_text_buffer ampstart ampend) else print_warning (Aucun document ouvert)

Bien sucircr il ne faut pas oublier de libeacuterer la meacutemoire

callbackc g_free (docsactif-gtchemin) docsactif-gtchemin = NULL docsactif-gtp_text_view = NULL g_free (docsactif) docsactif = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 30 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour symboliser la fermeture dun document nous deacutesactivons le GtkTextView lors de la fermeture (ne pas oublierde le faire aussi dans mainc)

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) FALSE)

Et nous le reacuteactivons lors de louverture si celle si reacuteussie

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Lorsque lutilisateur quitte lapplication il faut bien sucircr fermer le document sil y en a un ouvert

void cb_quit (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data) gtk_main_quit()

Et aussi lorsquil creacuteeacute un nouveau document (et par conseacutequent lorsquil ouvre un fichier puisque lon fait appel agravecb_new)

void cb_new (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data)

X-C - Enregistrer avant de fermer

Si le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde geacuteneacuteralement le programme le signale agrave lutilisateur etlui propose de sauvegarder ou dannuler la fermeture Pour se faire nous devons modifier la fonction cb_close avantde fermer le document nous allons afficher une boicircte de dialogue

Pour creacuteer une boicircte de dialogue simplement il existe la classe GtkDialog et comme nous avons besoin de boutons(pour que lutilisateur fasse son choix) nous allons creacuteer notre boicircte avec la fonction

GtkWidget gtk_dialog_new_with_buttons (const gchar title GtkWindow parent GtkDialogFlags flags const gchar first_button_text )

Nous retrouvons les mecircmes options que pour le GtkFileChooserDialog mis agrave part option du type GtkDialogFlags

typedef enum GTK_DIALOG_MODAL = 1 ltlt 0 appel gtk_window_set_modal (win TRUE) GTK_DIALOG_DESTROY_WITH_PARENT = 1 ltlt 1 appel gtk_window_set_destroy_with_parent () GTK_DIALOG_NO_SEPARATOR = 1 ltlt 2 Pas de barre de separation au dessus des boutons GtkDialogFlags

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 31 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Nous nous contenterons de rendre notre fenecirctre modale (7)

Pour avoir accegraves agrave notre fenecirctre principale nous ajoutons un champs p_main_window agrave notre structure globaledocs_t que nous initialisons dans la fonction main

mainc docsp_main_window = GTK_WINDOW (p_window)

Il nous reste plus qua creacuteer notre boicircte de dialogue avec trois boutons Oui Non Annuler

callbackc if (docsactif-gtsauve) GtkWidget p_dialog = NULL

p_dialog = gtk_dialog_new_with_buttons (Sauvegarder docsp_main_window GTK_DIALOG_MODAL GTK_STOCK_YES GTK_RESPONSE_YES GTK_STOCK_NO GTK_RESPONSE_NO GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL NULL)

Nous obtenons donc une structure de type GtkDialog

typedef struct GtkWidget vbox GtkWidget action_area GtkDialog

Nous remarquons que cette structure contient deux membres qui permettent dacceacuteder agrave une GtkBox ougrave nous allonsajouter le contenu de la fenecirctre et agrave la partie contenant les boutons

Ensuite la construction de la fenecirctre est identique agrave celle de la fenecirctre principale ici nous nous contenterons dajouterun GtkLabel

callbackc GtkWidget p_label = NULL p_label = gtk_label_new (Voulez-vous sauvegarder les modifications ) gtk_box_pack_start (GTK_BOX (GTK_DIALOG (p_dialog)-gtvbox) p_label TRUE TRUE 0)

Une fois notre fenecirctre precircte il suffit de faire appel agrave la fonction gtk_dialog_run qui va afficher notre GtkDialog et nousretourner le reacuteponse id correspondant au bouton cliqueacute par lutilisateur

callbackc switch (gtk_dialog_run (GTK_DIALOG (p_dialog))) case GTK_RESPONSE_YES cb_save (p_widget user_data) break case GTK_RESPONSE_NO break case GTK_RESPONSE_CANCEL gtk_widget_destroy (p_dialog) return break

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 32 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc gtk_widget_destroy (p_dialog)

Si lutilisateur clique sur non on ne fait rien (le document sera simplement fermeacute) sur oui on enregistre avant defermer et pour finir sil annule on quitte la fonction

X-D - Code source

chapitre10zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 33 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XI - Les barres de deacutefilement

XI-A - Aperccedilu

Cliquez pour agrandir

XI-B - Ajouter des barres de deacutefilement

Apregraves le dernier chapitre quelque peu laborieux voici une partie plus simple mais qui va rendre notre applicationplus pratique En effet si vous avez essayeacute douvrir un fichier de grande taille vous avez pu remarquer que pourpouvoir lire la fin du fichier il fallait utiliser les touches du clavier pas tregraves convivial

Pour rendre la navigation plus aiseacutee on utilise des barres de deacutefilement

mainc GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_scrolled_window TRUE TRUE 0)

Creation de la zone de texte gtk_container_add (GTK_CONTAINER (p_scrolled_window) p_text_view)

Le constructeur de notre GtkScrolledWindow prend en argument deux GtkAdjustment qui permettent de deacutefinirdiffeacuterentes proprieacuteteacutes de la barre de deacutefilement (taille dune page la position de deacutepart) nous laissons GTK+ faireen passant NULL

Cest un bon deacutebut mais estheacutetiquement on peut faire mieux mecircme sil nest pas utile davoir une barre de deacutefilementelle est quand mecircme afficheacutee On peut demander agrave GTK+ de les afficher que si cela est neacutecessaire

mainc gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC)

En fait nous avons de la chance car la classe GtkTextView fait partie des widget qui supporte de faccedilon native les barresde deacutefilement Comment le savoir Ce genre de widget possegravede une ou deux proprieacuteteacutes de type GtkAdjustment (unepour la barre verticale lautre pour la barre horizontale) Actuellement seulement trois classes en sont capables lesGtkTextView les GtkTreeView et les GtkLayout

Comment faire pour les autres widgets Il faut passer par une classe adaptateur GtkViewport afin de creacuteer lesGtkAdjustment

XI-C - Code source

chapitre11zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 34 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XII - Les menus

XII-A - Aperccedilu

Cliquez pour agrandir

XII-B - Creacuteation du menu

Pour simplifier nous avons utiliseacute des boutons pour permettre agrave lutilisateur de creacuteer un document ouvrir un fichierMais il est plus courant dutiliser un menu pour afficher ces options GTK+ propose trois maniegraveres de creacuteer un menu

bull GtkItemFactory cette meacutethode est obsolegravete depuis la version 24 de GTK+

bull GtkUIManager cest ce quon appel une usine agrave gaz pour en savoir plus vous pouvez vous reporter aututoriel Utilisation de GtkUIManager

bull GtkMenu cest ce widget que nous allons eacutetudier il permet de creacuteer un menu manuellement (agrave lopposeacute deGtkUIManager)

Un menu selon GTK+ est composeacute de plusieurs eacuteleacutements

bull GtkMenuBar la barre de menu elle-mecircme

bull GtkMenu la partie deacuteroulante qui contient les diffeacuterents eacuteleacutements

bull GtkMenuItem cest sur ce widget que lutilisateur clique pour lancer une action

Pour commencer faisons linventaire de ce que nous avons besoin

bull Un GtkMenuBar qui sert de base au menu

bull Un GtkMenu pour commencer nous nous aurons dun menu Fichier

bull Six GtkMenuItem pour remplacer nos six boutons

Commenccedilons par la creacuteation du menu nous mettons ce code dans un nouveau fichier dont seul la fonction menu_newsera accessible

menucGtkMenuBar menu_new (gpointer user_data) GtkWidget p_menu_bar = NULL

p_menu_bar = gtk_menu_bar_new () return GTK_MENU_BAR (p_menu_bar)

Le paramegravetre user_data nous servira lors de la connexion des callbacks (nous en avons besoin pour les fonctionscb_new et cb_open)

Ensuite nous allons creacuteer notre sous menu Fichier

menuc Menu Fichier

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 35 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

menuc GtkWidget p_menu = NULL GtkWidget p_menu_item = NULL

p_menu = gtk_menu_new () p_menu_item = gtk_menu_item_new_with_mnemonic (_Fichier) gtk_menu_item_set_submenu (GTK_MENU_ITEM (p_menu_item) p_menu) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu_bar) p_menu_item) return GTK_MENU_BAR (p_menu_bar)

Un sous menu est en fait un GtkMenuItem auquel on assigne un GtkMenu Il faut bien sucircr terminer la creacuteation dusous-menu en lajoutant agrave la barre de menu

Pour finir nous creacuteons les eacuteleacutements du menu les GtkItemMenu Il existe plusieurs types deacuteleacutements (comparableaux diffeacuterents types de bouton) pour commencer nous nutiliserons que le type de base Comme cette opeacuteration estreacutepeacutetitive nous allons creacuteer une fonction pour le faire

menucstatic void menu_item_new (GtkMenu p_menu const gchar title GCallback callback gpointer user_data) GtkWidget p_menu_item = NULL

p_menu_item = gtk_menu_item_new_with_mnemonic (title) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu) p_menu_item) g_signal_connect (G_OBJECT (p_menu_item) activate callback user_data)

Pour permettre agrave lutilisateur dacceacuteder aux diffeacuterents eacuteleacutements du menu agrave laide de la touche ltAltgt nous utilisonsdes mneacutemoniques par exemple pour quitter leacutediteur il suffit de faite Alt+F puis Q Et voici le code pour creacuteer nossix eacuteleacutements du menu

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau G_CALLBACK (cb_new) user_data) menu_item_new (GTK_MENU (p_menu) _Ouvrir G_CALLBACK (cb_open) user_data) menu_item_new (GTK_MENU (p_menu) _Enregistrer G_CALLBACK (cb_save) user_data) menu_item_new (GTK_MENU (p_menu) Enregistrer _sous G_CALLBACK (cb_saveas) user_data) menu_item_new (GTK_MENU (p_menu) _Fermer G_CALLBACK (cb_close) user_data) menu_item_new (GTK_MENU (p_menu) _Quitter G_CALLBACK (cb_quit) user_data)

Voilagrave notre menu est creacuteeacute il nous reste plus quagrave linteacutegrer agrave notre fenecirctre

mainc gtk_box_pack_start (GTK_BOX (p_main_box) GTK_WIDGET (menu_new (p_text_view)) FALSE FALSE 0)

Le problegraveme cest que nous avons besoin de passer le GtkTextView lors de la creacuteation du menu (qui est utiliseacute par lesfonctions cb_new et cb_open) or celui-ci est creacuteeacute apregraves le menu (puisque nous creacuteons les widgets dans lordre ougrave ilfaut les inteacutegrer agrave linterface (8) ) nous devons creacuteer le GtkTextView (seul lappel agrave gtk_text_view_new est deacuteplaceacute)

XII-C - Code source

chapitre12zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 36 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIII - Les barres doutils

XIII-A - Aperccedilu

Cliquez pour agrandir

XIII-B - Creacuteation dune barre doutils

La creacuteation dune barre doutils ressemble fort agrave celle dun menu en plus simple puisquil ny a pas de sous menu on creacutee notre barre doutils (gtk_toolbar_new) puis les eacuteleacutements de la barre pour cela on utilise des boutons(gtk_tool_button_new_from_stock) que lon inseacutere dans la barre (gtk_toolbar_insert) Pas conseacutequent notre fichierbarreoutilsc ressemble agrave menuc

barreoutilscinclude ltgtkgtkhgtinclude callbackhinclude barreoutilsh

static void toolbar_item_new (GtkToolbar const gchar GCallback gpointer)

GtkToolbar toolbar_new (gpointer user_data) GtkWidget p_toolbar = NULL

p_toolbar = gtk_toolbar_new () toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_NEW G_CALLBACK (cb_new) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_OPEN G_CALLBACK (cb_open) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE G_CALLBACK (cb_save) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE_AS G_CALLBACK (cb_saveas) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_CLOSE G_CALLBACK (cb_close) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_QUIT G_CALLBACK (cb_quit) user_data) return GTK_TOOLBAR (p_toolbar)

static void toolbar_item_new (GtkToolbar p_toolbar const gchar stock_id GCallback callback gpointer user_data) GtkToolItem p_tool_item = NULL

p_tool_item = gtk_tool_button_new_from_stock (stock_id) g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data) gtk_toolbar_insert (p_toolbar p_tool_item -1)

Le code nest pas complet car lorsque jexeacutecute le programme GTK+ affiche en plus des icocircnes le texte sous lesboutons Pour modifier cela il suffit dajouter une ligne de code

barreoutilsc gtk_toolbar_set_style (GTK_TOOLBAR (p_toolbar) GTK_TOOLBAR_ICONS)

Pourquoi gtk_tool_button_new_from_stock retourne un GtkToolItem et non un GtkWidgetcomme nous avons eacuteteacute habitueacute jusquagrave preacutesent Il sagit dune bizarrerie de GTK+ dontje ne connais pas la raison

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 37 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour anticiper un changement dinterface (dans GTK+ 30 peut ecirctre ) nous aurions pueacutecrire

Gtkwidget p_tool_item = NULL

p_tool_item = GTK_WIDGET (gtk_tool_button_new_from_stock (stock_id))g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data)gtk_toolbar_insert (p_toolbar GTK_TOOL_ITEM (p_tool_item) -1)

XIII-C - Code source

chapitre13zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 38 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIV - Les racourcis clavier

XIV-A - Aperccedilu

Cliquez pour agrandir

XIV-B - Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mneacutemoniques ces derniers permettent dacceacuteder agrave un eacuteleacutementseacutequentiellement alors que les raccourcis appellent une fonction si lutilisateur appuie simultaneacutement sur une ouplusieurs touches (geacuteneacuteralement de la forme ltModificateurgtTouche ougrave Modificateur repreacutesente les touches ShiftAlt et Control) Ce raccourci peut ecirctre attacheacute agrave un eacuteleacutement du menu mais ceci nest pas obligatoire

Les raccourcis sont regroupeacutes en groupe dans un GtkAccelGroup quil faut commencer par creacuteer

raccourciscinclude ltgtkgtkhgtinclude callbackhinclude raccourcish

GtkAccelGroup accel_group_new (gpointer user_data) GtkAccelGroup p_accel_group = NULL

p_accel_group = gtk_accel_group_new () return p_accel_group

Vous commencez agrave avoir lhabitude de cette organisation nous allons donc creacuteer une fonction qui va se chargerdajouter un raccourci au groupe

raccourciscstatic void accelerator_new (GtkAccelGroup p_accel_group const gchar accelerator const gchar accel_path GCallback callback gpointer user_data) guint key GdkModifierType mods GClosure closure = NULL

gtk_accelerator_parse (accelerator ampkey ampmods) closure = g_cclosure_new (callback user_data NULL) gtk_accel_group_connect (p_accel_group key mods GTK_ACCEL_VISIBLE closure) gtk_accel_map_add_entry (accel_path key mods)

La fonction gtk_accelerator_parse permet de deacutecomposer une chaicircne de caractegraveres de la forme ltControlgtF1 ouencore ltAltgtA en numeacutero de touche et modificateur

En plus des touches pour creacuteer un raccourci clavier nous avons besoin dune fonction agrave appeler lorsque lutilisateurappuie sur les touches speacutecifieacutees gtk_accel_group_connect attend une fonction du type GClosure regardons ladocumentation de gobject pour savoir agrave quoi cela correspond

typedef struct

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 30 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour symboliser la fermeture dun document nous deacutesactivons le GtkTextView lors de la fermeture (ne pas oublierde le faire aussi dans mainc)

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) FALSE)

Et nous le reacuteactivons lors de louverture si celle si reacuteussie

callbackc gtk_widget_set_sensitive (GTK_WIDGET (docsactif-gtp_text_view) TRUE)

Lorsque lutilisateur quitte lapplication il faut bien sucircr fermer le document sil y en a un ouvert

void cb_quit (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data) gtk_main_quit()

Et aussi lorsquil creacuteeacute un nouveau document (et par conseacutequent lorsquil ouvre un fichier puisque lon fait appel agravecb_new)

void cb_new (GtkWidget p_widget gpointer user_data) if (docsactif) cb_close (p_widget user_data)

X-C - Enregistrer avant de fermer

Si le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde geacuteneacuteralement le programme le signale agrave lutilisateur etlui propose de sauvegarder ou dannuler la fermeture Pour se faire nous devons modifier la fonction cb_close avantde fermer le document nous allons afficher une boicircte de dialogue

Pour creacuteer une boicircte de dialogue simplement il existe la classe GtkDialog et comme nous avons besoin de boutons(pour que lutilisateur fasse son choix) nous allons creacuteer notre boicircte avec la fonction

GtkWidget gtk_dialog_new_with_buttons (const gchar title GtkWindow parent GtkDialogFlags flags const gchar first_button_text )

Nous retrouvons les mecircmes options que pour le GtkFileChooserDialog mis agrave part option du type GtkDialogFlags

typedef enum GTK_DIALOG_MODAL = 1 ltlt 0 appel gtk_window_set_modal (win TRUE) GTK_DIALOG_DESTROY_WITH_PARENT = 1 ltlt 1 appel gtk_window_set_destroy_with_parent () GTK_DIALOG_NO_SEPARATOR = 1 ltlt 2 Pas de barre de separation au dessus des boutons GtkDialogFlags

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 31 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Nous nous contenterons de rendre notre fenecirctre modale (7)

Pour avoir accegraves agrave notre fenecirctre principale nous ajoutons un champs p_main_window agrave notre structure globaledocs_t que nous initialisons dans la fonction main

mainc docsp_main_window = GTK_WINDOW (p_window)

Il nous reste plus qua creacuteer notre boicircte de dialogue avec trois boutons Oui Non Annuler

callbackc if (docsactif-gtsauve) GtkWidget p_dialog = NULL

p_dialog = gtk_dialog_new_with_buttons (Sauvegarder docsp_main_window GTK_DIALOG_MODAL GTK_STOCK_YES GTK_RESPONSE_YES GTK_STOCK_NO GTK_RESPONSE_NO GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL NULL)

Nous obtenons donc une structure de type GtkDialog

typedef struct GtkWidget vbox GtkWidget action_area GtkDialog

Nous remarquons que cette structure contient deux membres qui permettent dacceacuteder agrave une GtkBox ougrave nous allonsajouter le contenu de la fenecirctre et agrave la partie contenant les boutons

Ensuite la construction de la fenecirctre est identique agrave celle de la fenecirctre principale ici nous nous contenterons dajouterun GtkLabel

callbackc GtkWidget p_label = NULL p_label = gtk_label_new (Voulez-vous sauvegarder les modifications ) gtk_box_pack_start (GTK_BOX (GTK_DIALOG (p_dialog)-gtvbox) p_label TRUE TRUE 0)

Une fois notre fenecirctre precircte il suffit de faire appel agrave la fonction gtk_dialog_run qui va afficher notre GtkDialog et nousretourner le reacuteponse id correspondant au bouton cliqueacute par lutilisateur

callbackc switch (gtk_dialog_run (GTK_DIALOG (p_dialog))) case GTK_RESPONSE_YES cb_save (p_widget user_data) break case GTK_RESPONSE_NO break case GTK_RESPONSE_CANCEL gtk_widget_destroy (p_dialog) return break

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 32 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc gtk_widget_destroy (p_dialog)

Si lutilisateur clique sur non on ne fait rien (le document sera simplement fermeacute) sur oui on enregistre avant defermer et pour finir sil annule on quitte la fonction

X-D - Code source

chapitre10zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 33 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XI - Les barres de deacutefilement

XI-A - Aperccedilu

Cliquez pour agrandir

XI-B - Ajouter des barres de deacutefilement

Apregraves le dernier chapitre quelque peu laborieux voici une partie plus simple mais qui va rendre notre applicationplus pratique En effet si vous avez essayeacute douvrir un fichier de grande taille vous avez pu remarquer que pourpouvoir lire la fin du fichier il fallait utiliser les touches du clavier pas tregraves convivial

Pour rendre la navigation plus aiseacutee on utilise des barres de deacutefilement

mainc GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_scrolled_window TRUE TRUE 0)

Creation de la zone de texte gtk_container_add (GTK_CONTAINER (p_scrolled_window) p_text_view)

Le constructeur de notre GtkScrolledWindow prend en argument deux GtkAdjustment qui permettent de deacutefinirdiffeacuterentes proprieacuteteacutes de la barre de deacutefilement (taille dune page la position de deacutepart) nous laissons GTK+ faireen passant NULL

Cest un bon deacutebut mais estheacutetiquement on peut faire mieux mecircme sil nest pas utile davoir une barre de deacutefilementelle est quand mecircme afficheacutee On peut demander agrave GTK+ de les afficher que si cela est neacutecessaire

mainc gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC)

En fait nous avons de la chance car la classe GtkTextView fait partie des widget qui supporte de faccedilon native les barresde deacutefilement Comment le savoir Ce genre de widget possegravede une ou deux proprieacuteteacutes de type GtkAdjustment (unepour la barre verticale lautre pour la barre horizontale) Actuellement seulement trois classes en sont capables lesGtkTextView les GtkTreeView et les GtkLayout

Comment faire pour les autres widgets Il faut passer par une classe adaptateur GtkViewport afin de creacuteer lesGtkAdjustment

XI-C - Code source

chapitre11zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 34 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XII - Les menus

XII-A - Aperccedilu

Cliquez pour agrandir

XII-B - Creacuteation du menu

Pour simplifier nous avons utiliseacute des boutons pour permettre agrave lutilisateur de creacuteer un document ouvrir un fichierMais il est plus courant dutiliser un menu pour afficher ces options GTK+ propose trois maniegraveres de creacuteer un menu

bull GtkItemFactory cette meacutethode est obsolegravete depuis la version 24 de GTK+

bull GtkUIManager cest ce quon appel une usine agrave gaz pour en savoir plus vous pouvez vous reporter aututoriel Utilisation de GtkUIManager

bull GtkMenu cest ce widget que nous allons eacutetudier il permet de creacuteer un menu manuellement (agrave lopposeacute deGtkUIManager)

Un menu selon GTK+ est composeacute de plusieurs eacuteleacutements

bull GtkMenuBar la barre de menu elle-mecircme

bull GtkMenu la partie deacuteroulante qui contient les diffeacuterents eacuteleacutements

bull GtkMenuItem cest sur ce widget que lutilisateur clique pour lancer une action

Pour commencer faisons linventaire de ce que nous avons besoin

bull Un GtkMenuBar qui sert de base au menu

bull Un GtkMenu pour commencer nous nous aurons dun menu Fichier

bull Six GtkMenuItem pour remplacer nos six boutons

Commenccedilons par la creacuteation du menu nous mettons ce code dans un nouveau fichier dont seul la fonction menu_newsera accessible

menucGtkMenuBar menu_new (gpointer user_data) GtkWidget p_menu_bar = NULL

p_menu_bar = gtk_menu_bar_new () return GTK_MENU_BAR (p_menu_bar)

Le paramegravetre user_data nous servira lors de la connexion des callbacks (nous en avons besoin pour les fonctionscb_new et cb_open)

Ensuite nous allons creacuteer notre sous menu Fichier

menuc Menu Fichier

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 35 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

menuc GtkWidget p_menu = NULL GtkWidget p_menu_item = NULL

p_menu = gtk_menu_new () p_menu_item = gtk_menu_item_new_with_mnemonic (_Fichier) gtk_menu_item_set_submenu (GTK_MENU_ITEM (p_menu_item) p_menu) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu_bar) p_menu_item) return GTK_MENU_BAR (p_menu_bar)

Un sous menu est en fait un GtkMenuItem auquel on assigne un GtkMenu Il faut bien sucircr terminer la creacuteation dusous-menu en lajoutant agrave la barre de menu

Pour finir nous creacuteons les eacuteleacutements du menu les GtkItemMenu Il existe plusieurs types deacuteleacutements (comparableaux diffeacuterents types de bouton) pour commencer nous nutiliserons que le type de base Comme cette opeacuteration estreacutepeacutetitive nous allons creacuteer une fonction pour le faire

menucstatic void menu_item_new (GtkMenu p_menu const gchar title GCallback callback gpointer user_data) GtkWidget p_menu_item = NULL

p_menu_item = gtk_menu_item_new_with_mnemonic (title) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu) p_menu_item) g_signal_connect (G_OBJECT (p_menu_item) activate callback user_data)

Pour permettre agrave lutilisateur dacceacuteder aux diffeacuterents eacuteleacutements du menu agrave laide de la touche ltAltgt nous utilisonsdes mneacutemoniques par exemple pour quitter leacutediteur il suffit de faite Alt+F puis Q Et voici le code pour creacuteer nossix eacuteleacutements du menu

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau G_CALLBACK (cb_new) user_data) menu_item_new (GTK_MENU (p_menu) _Ouvrir G_CALLBACK (cb_open) user_data) menu_item_new (GTK_MENU (p_menu) _Enregistrer G_CALLBACK (cb_save) user_data) menu_item_new (GTK_MENU (p_menu) Enregistrer _sous G_CALLBACK (cb_saveas) user_data) menu_item_new (GTK_MENU (p_menu) _Fermer G_CALLBACK (cb_close) user_data) menu_item_new (GTK_MENU (p_menu) _Quitter G_CALLBACK (cb_quit) user_data)

Voilagrave notre menu est creacuteeacute il nous reste plus quagrave linteacutegrer agrave notre fenecirctre

mainc gtk_box_pack_start (GTK_BOX (p_main_box) GTK_WIDGET (menu_new (p_text_view)) FALSE FALSE 0)

Le problegraveme cest que nous avons besoin de passer le GtkTextView lors de la creacuteation du menu (qui est utiliseacute par lesfonctions cb_new et cb_open) or celui-ci est creacuteeacute apregraves le menu (puisque nous creacuteons les widgets dans lordre ougrave ilfaut les inteacutegrer agrave linterface (8) ) nous devons creacuteer le GtkTextView (seul lappel agrave gtk_text_view_new est deacuteplaceacute)

XII-C - Code source

chapitre12zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 36 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIII - Les barres doutils

XIII-A - Aperccedilu

Cliquez pour agrandir

XIII-B - Creacuteation dune barre doutils

La creacuteation dune barre doutils ressemble fort agrave celle dun menu en plus simple puisquil ny a pas de sous menu on creacutee notre barre doutils (gtk_toolbar_new) puis les eacuteleacutements de la barre pour cela on utilise des boutons(gtk_tool_button_new_from_stock) que lon inseacutere dans la barre (gtk_toolbar_insert) Pas conseacutequent notre fichierbarreoutilsc ressemble agrave menuc

barreoutilscinclude ltgtkgtkhgtinclude callbackhinclude barreoutilsh

static void toolbar_item_new (GtkToolbar const gchar GCallback gpointer)

GtkToolbar toolbar_new (gpointer user_data) GtkWidget p_toolbar = NULL

p_toolbar = gtk_toolbar_new () toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_NEW G_CALLBACK (cb_new) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_OPEN G_CALLBACK (cb_open) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE G_CALLBACK (cb_save) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE_AS G_CALLBACK (cb_saveas) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_CLOSE G_CALLBACK (cb_close) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_QUIT G_CALLBACK (cb_quit) user_data) return GTK_TOOLBAR (p_toolbar)

static void toolbar_item_new (GtkToolbar p_toolbar const gchar stock_id GCallback callback gpointer user_data) GtkToolItem p_tool_item = NULL

p_tool_item = gtk_tool_button_new_from_stock (stock_id) g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data) gtk_toolbar_insert (p_toolbar p_tool_item -1)

Le code nest pas complet car lorsque jexeacutecute le programme GTK+ affiche en plus des icocircnes le texte sous lesboutons Pour modifier cela il suffit dajouter une ligne de code

barreoutilsc gtk_toolbar_set_style (GTK_TOOLBAR (p_toolbar) GTK_TOOLBAR_ICONS)

Pourquoi gtk_tool_button_new_from_stock retourne un GtkToolItem et non un GtkWidgetcomme nous avons eacuteteacute habitueacute jusquagrave preacutesent Il sagit dune bizarrerie de GTK+ dontje ne connais pas la raison

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 37 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour anticiper un changement dinterface (dans GTK+ 30 peut ecirctre ) nous aurions pueacutecrire

Gtkwidget p_tool_item = NULL

p_tool_item = GTK_WIDGET (gtk_tool_button_new_from_stock (stock_id))g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data)gtk_toolbar_insert (p_toolbar GTK_TOOL_ITEM (p_tool_item) -1)

XIII-C - Code source

chapitre13zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 38 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIV - Les racourcis clavier

XIV-A - Aperccedilu

Cliquez pour agrandir

XIV-B - Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mneacutemoniques ces derniers permettent dacceacuteder agrave un eacuteleacutementseacutequentiellement alors que les raccourcis appellent une fonction si lutilisateur appuie simultaneacutement sur une ouplusieurs touches (geacuteneacuteralement de la forme ltModificateurgtTouche ougrave Modificateur repreacutesente les touches ShiftAlt et Control) Ce raccourci peut ecirctre attacheacute agrave un eacuteleacutement du menu mais ceci nest pas obligatoire

Les raccourcis sont regroupeacutes en groupe dans un GtkAccelGroup quil faut commencer par creacuteer

raccourciscinclude ltgtkgtkhgtinclude callbackhinclude raccourcish

GtkAccelGroup accel_group_new (gpointer user_data) GtkAccelGroup p_accel_group = NULL

p_accel_group = gtk_accel_group_new () return p_accel_group

Vous commencez agrave avoir lhabitude de cette organisation nous allons donc creacuteer une fonction qui va se chargerdajouter un raccourci au groupe

raccourciscstatic void accelerator_new (GtkAccelGroup p_accel_group const gchar accelerator const gchar accel_path GCallback callback gpointer user_data) guint key GdkModifierType mods GClosure closure = NULL

gtk_accelerator_parse (accelerator ampkey ampmods) closure = g_cclosure_new (callback user_data NULL) gtk_accel_group_connect (p_accel_group key mods GTK_ACCEL_VISIBLE closure) gtk_accel_map_add_entry (accel_path key mods)

La fonction gtk_accelerator_parse permet de deacutecomposer une chaicircne de caractegraveres de la forme ltControlgtF1 ouencore ltAltgtA en numeacutero de touche et modificateur

En plus des touches pour creacuteer un raccourci clavier nous avons besoin dune fonction agrave appeler lorsque lutilisateurappuie sur les touches speacutecifieacutees gtk_accel_group_connect attend une fonction du type GClosure regardons ladocumentation de gobject pour savoir agrave quoi cela correspond

typedef struct

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 31 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Nous nous contenterons de rendre notre fenecirctre modale (7)

Pour avoir accegraves agrave notre fenecirctre principale nous ajoutons un champs p_main_window agrave notre structure globaledocs_t que nous initialisons dans la fonction main

mainc docsp_main_window = GTK_WINDOW (p_window)

Il nous reste plus qua creacuteer notre boicircte de dialogue avec trois boutons Oui Non Annuler

callbackc if (docsactif-gtsauve) GtkWidget p_dialog = NULL

p_dialog = gtk_dialog_new_with_buttons (Sauvegarder docsp_main_window GTK_DIALOG_MODAL GTK_STOCK_YES GTK_RESPONSE_YES GTK_STOCK_NO GTK_RESPONSE_NO GTK_STOCK_CANCEL GTK_RESPONSE_CANCEL NULL)

Nous obtenons donc une structure de type GtkDialog

typedef struct GtkWidget vbox GtkWidget action_area GtkDialog

Nous remarquons que cette structure contient deux membres qui permettent dacceacuteder agrave une GtkBox ougrave nous allonsajouter le contenu de la fenecirctre et agrave la partie contenant les boutons

Ensuite la construction de la fenecirctre est identique agrave celle de la fenecirctre principale ici nous nous contenterons dajouterun GtkLabel

callbackc GtkWidget p_label = NULL p_label = gtk_label_new (Voulez-vous sauvegarder les modifications ) gtk_box_pack_start (GTK_BOX (GTK_DIALOG (p_dialog)-gtvbox) p_label TRUE TRUE 0)

Une fois notre fenecirctre precircte il suffit de faire appel agrave la fonction gtk_dialog_run qui va afficher notre GtkDialog et nousretourner le reacuteponse id correspondant au bouton cliqueacute par lutilisateur

callbackc switch (gtk_dialog_run (GTK_DIALOG (p_dialog))) case GTK_RESPONSE_YES cb_save (p_widget user_data) break case GTK_RESPONSE_NO break case GTK_RESPONSE_CANCEL gtk_widget_destroy (p_dialog) return break

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 32 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc gtk_widget_destroy (p_dialog)

Si lutilisateur clique sur non on ne fait rien (le document sera simplement fermeacute) sur oui on enregistre avant defermer et pour finir sil annule on quitte la fonction

X-D - Code source

chapitre10zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 33 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XI - Les barres de deacutefilement

XI-A - Aperccedilu

Cliquez pour agrandir

XI-B - Ajouter des barres de deacutefilement

Apregraves le dernier chapitre quelque peu laborieux voici une partie plus simple mais qui va rendre notre applicationplus pratique En effet si vous avez essayeacute douvrir un fichier de grande taille vous avez pu remarquer que pourpouvoir lire la fin du fichier il fallait utiliser les touches du clavier pas tregraves convivial

Pour rendre la navigation plus aiseacutee on utilise des barres de deacutefilement

mainc GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_scrolled_window TRUE TRUE 0)

Creation de la zone de texte gtk_container_add (GTK_CONTAINER (p_scrolled_window) p_text_view)

Le constructeur de notre GtkScrolledWindow prend en argument deux GtkAdjustment qui permettent de deacutefinirdiffeacuterentes proprieacuteteacutes de la barre de deacutefilement (taille dune page la position de deacutepart) nous laissons GTK+ faireen passant NULL

Cest un bon deacutebut mais estheacutetiquement on peut faire mieux mecircme sil nest pas utile davoir une barre de deacutefilementelle est quand mecircme afficheacutee On peut demander agrave GTK+ de les afficher que si cela est neacutecessaire

mainc gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC)

En fait nous avons de la chance car la classe GtkTextView fait partie des widget qui supporte de faccedilon native les barresde deacutefilement Comment le savoir Ce genre de widget possegravede une ou deux proprieacuteteacutes de type GtkAdjustment (unepour la barre verticale lautre pour la barre horizontale) Actuellement seulement trois classes en sont capables lesGtkTextView les GtkTreeView et les GtkLayout

Comment faire pour les autres widgets Il faut passer par une classe adaptateur GtkViewport afin de creacuteer lesGtkAdjustment

XI-C - Code source

chapitre11zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 34 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XII - Les menus

XII-A - Aperccedilu

Cliquez pour agrandir

XII-B - Creacuteation du menu

Pour simplifier nous avons utiliseacute des boutons pour permettre agrave lutilisateur de creacuteer un document ouvrir un fichierMais il est plus courant dutiliser un menu pour afficher ces options GTK+ propose trois maniegraveres de creacuteer un menu

bull GtkItemFactory cette meacutethode est obsolegravete depuis la version 24 de GTK+

bull GtkUIManager cest ce quon appel une usine agrave gaz pour en savoir plus vous pouvez vous reporter aututoriel Utilisation de GtkUIManager

bull GtkMenu cest ce widget que nous allons eacutetudier il permet de creacuteer un menu manuellement (agrave lopposeacute deGtkUIManager)

Un menu selon GTK+ est composeacute de plusieurs eacuteleacutements

bull GtkMenuBar la barre de menu elle-mecircme

bull GtkMenu la partie deacuteroulante qui contient les diffeacuterents eacuteleacutements

bull GtkMenuItem cest sur ce widget que lutilisateur clique pour lancer une action

Pour commencer faisons linventaire de ce que nous avons besoin

bull Un GtkMenuBar qui sert de base au menu

bull Un GtkMenu pour commencer nous nous aurons dun menu Fichier

bull Six GtkMenuItem pour remplacer nos six boutons

Commenccedilons par la creacuteation du menu nous mettons ce code dans un nouveau fichier dont seul la fonction menu_newsera accessible

menucGtkMenuBar menu_new (gpointer user_data) GtkWidget p_menu_bar = NULL

p_menu_bar = gtk_menu_bar_new () return GTK_MENU_BAR (p_menu_bar)

Le paramegravetre user_data nous servira lors de la connexion des callbacks (nous en avons besoin pour les fonctionscb_new et cb_open)

Ensuite nous allons creacuteer notre sous menu Fichier

menuc Menu Fichier

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 35 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

menuc GtkWidget p_menu = NULL GtkWidget p_menu_item = NULL

p_menu = gtk_menu_new () p_menu_item = gtk_menu_item_new_with_mnemonic (_Fichier) gtk_menu_item_set_submenu (GTK_MENU_ITEM (p_menu_item) p_menu) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu_bar) p_menu_item) return GTK_MENU_BAR (p_menu_bar)

Un sous menu est en fait un GtkMenuItem auquel on assigne un GtkMenu Il faut bien sucircr terminer la creacuteation dusous-menu en lajoutant agrave la barre de menu

Pour finir nous creacuteons les eacuteleacutements du menu les GtkItemMenu Il existe plusieurs types deacuteleacutements (comparableaux diffeacuterents types de bouton) pour commencer nous nutiliserons que le type de base Comme cette opeacuteration estreacutepeacutetitive nous allons creacuteer une fonction pour le faire

menucstatic void menu_item_new (GtkMenu p_menu const gchar title GCallback callback gpointer user_data) GtkWidget p_menu_item = NULL

p_menu_item = gtk_menu_item_new_with_mnemonic (title) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu) p_menu_item) g_signal_connect (G_OBJECT (p_menu_item) activate callback user_data)

Pour permettre agrave lutilisateur dacceacuteder aux diffeacuterents eacuteleacutements du menu agrave laide de la touche ltAltgt nous utilisonsdes mneacutemoniques par exemple pour quitter leacutediteur il suffit de faite Alt+F puis Q Et voici le code pour creacuteer nossix eacuteleacutements du menu

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau G_CALLBACK (cb_new) user_data) menu_item_new (GTK_MENU (p_menu) _Ouvrir G_CALLBACK (cb_open) user_data) menu_item_new (GTK_MENU (p_menu) _Enregistrer G_CALLBACK (cb_save) user_data) menu_item_new (GTK_MENU (p_menu) Enregistrer _sous G_CALLBACK (cb_saveas) user_data) menu_item_new (GTK_MENU (p_menu) _Fermer G_CALLBACK (cb_close) user_data) menu_item_new (GTK_MENU (p_menu) _Quitter G_CALLBACK (cb_quit) user_data)

Voilagrave notre menu est creacuteeacute il nous reste plus quagrave linteacutegrer agrave notre fenecirctre

mainc gtk_box_pack_start (GTK_BOX (p_main_box) GTK_WIDGET (menu_new (p_text_view)) FALSE FALSE 0)

Le problegraveme cest que nous avons besoin de passer le GtkTextView lors de la creacuteation du menu (qui est utiliseacute par lesfonctions cb_new et cb_open) or celui-ci est creacuteeacute apregraves le menu (puisque nous creacuteons les widgets dans lordre ougrave ilfaut les inteacutegrer agrave linterface (8) ) nous devons creacuteer le GtkTextView (seul lappel agrave gtk_text_view_new est deacuteplaceacute)

XII-C - Code source

chapitre12zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 36 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIII - Les barres doutils

XIII-A - Aperccedilu

Cliquez pour agrandir

XIII-B - Creacuteation dune barre doutils

La creacuteation dune barre doutils ressemble fort agrave celle dun menu en plus simple puisquil ny a pas de sous menu on creacutee notre barre doutils (gtk_toolbar_new) puis les eacuteleacutements de la barre pour cela on utilise des boutons(gtk_tool_button_new_from_stock) que lon inseacutere dans la barre (gtk_toolbar_insert) Pas conseacutequent notre fichierbarreoutilsc ressemble agrave menuc

barreoutilscinclude ltgtkgtkhgtinclude callbackhinclude barreoutilsh

static void toolbar_item_new (GtkToolbar const gchar GCallback gpointer)

GtkToolbar toolbar_new (gpointer user_data) GtkWidget p_toolbar = NULL

p_toolbar = gtk_toolbar_new () toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_NEW G_CALLBACK (cb_new) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_OPEN G_CALLBACK (cb_open) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE G_CALLBACK (cb_save) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE_AS G_CALLBACK (cb_saveas) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_CLOSE G_CALLBACK (cb_close) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_QUIT G_CALLBACK (cb_quit) user_data) return GTK_TOOLBAR (p_toolbar)

static void toolbar_item_new (GtkToolbar p_toolbar const gchar stock_id GCallback callback gpointer user_data) GtkToolItem p_tool_item = NULL

p_tool_item = gtk_tool_button_new_from_stock (stock_id) g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data) gtk_toolbar_insert (p_toolbar p_tool_item -1)

Le code nest pas complet car lorsque jexeacutecute le programme GTK+ affiche en plus des icocircnes le texte sous lesboutons Pour modifier cela il suffit dajouter une ligne de code

barreoutilsc gtk_toolbar_set_style (GTK_TOOLBAR (p_toolbar) GTK_TOOLBAR_ICONS)

Pourquoi gtk_tool_button_new_from_stock retourne un GtkToolItem et non un GtkWidgetcomme nous avons eacuteteacute habitueacute jusquagrave preacutesent Il sagit dune bizarrerie de GTK+ dontje ne connais pas la raison

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 37 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour anticiper un changement dinterface (dans GTK+ 30 peut ecirctre ) nous aurions pueacutecrire

Gtkwidget p_tool_item = NULL

p_tool_item = GTK_WIDGET (gtk_tool_button_new_from_stock (stock_id))g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data)gtk_toolbar_insert (p_toolbar GTK_TOOL_ITEM (p_tool_item) -1)

XIII-C - Code source

chapitre13zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 38 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIV - Les racourcis clavier

XIV-A - Aperccedilu

Cliquez pour agrandir

XIV-B - Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mneacutemoniques ces derniers permettent dacceacuteder agrave un eacuteleacutementseacutequentiellement alors que les raccourcis appellent une fonction si lutilisateur appuie simultaneacutement sur une ouplusieurs touches (geacuteneacuteralement de la forme ltModificateurgtTouche ougrave Modificateur repreacutesente les touches ShiftAlt et Control) Ce raccourci peut ecirctre attacheacute agrave un eacuteleacutement du menu mais ceci nest pas obligatoire

Les raccourcis sont regroupeacutes en groupe dans un GtkAccelGroup quil faut commencer par creacuteer

raccourciscinclude ltgtkgtkhgtinclude callbackhinclude raccourcish

GtkAccelGroup accel_group_new (gpointer user_data) GtkAccelGroup p_accel_group = NULL

p_accel_group = gtk_accel_group_new () return p_accel_group

Vous commencez agrave avoir lhabitude de cette organisation nous allons donc creacuteer une fonction qui va se chargerdajouter un raccourci au groupe

raccourciscstatic void accelerator_new (GtkAccelGroup p_accel_group const gchar accelerator const gchar accel_path GCallback callback gpointer user_data) guint key GdkModifierType mods GClosure closure = NULL

gtk_accelerator_parse (accelerator ampkey ampmods) closure = g_cclosure_new (callback user_data NULL) gtk_accel_group_connect (p_accel_group key mods GTK_ACCEL_VISIBLE closure) gtk_accel_map_add_entry (accel_path key mods)

La fonction gtk_accelerator_parse permet de deacutecomposer une chaicircne de caractegraveres de la forme ltControlgtF1 ouencore ltAltgtA en numeacutero de touche et modificateur

En plus des touches pour creacuteer un raccourci clavier nous avons besoin dune fonction agrave appeler lorsque lutilisateurappuie sur les touches speacutecifieacutees gtk_accel_group_connect attend une fonction du type GClosure regardons ladocumentation de gobject pour savoir agrave quoi cela correspond

typedef struct

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 32 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc gtk_widget_destroy (p_dialog)

Si lutilisateur clique sur non on ne fait rien (le document sera simplement fermeacute) sur oui on enregistre avant defermer et pour finir sil annule on quitte la fonction

X-D - Code source

chapitre10zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 33 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XI - Les barres de deacutefilement

XI-A - Aperccedilu

Cliquez pour agrandir

XI-B - Ajouter des barres de deacutefilement

Apregraves le dernier chapitre quelque peu laborieux voici une partie plus simple mais qui va rendre notre applicationplus pratique En effet si vous avez essayeacute douvrir un fichier de grande taille vous avez pu remarquer que pourpouvoir lire la fin du fichier il fallait utiliser les touches du clavier pas tregraves convivial

Pour rendre la navigation plus aiseacutee on utilise des barres de deacutefilement

mainc GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_scrolled_window TRUE TRUE 0)

Creation de la zone de texte gtk_container_add (GTK_CONTAINER (p_scrolled_window) p_text_view)

Le constructeur de notre GtkScrolledWindow prend en argument deux GtkAdjustment qui permettent de deacutefinirdiffeacuterentes proprieacuteteacutes de la barre de deacutefilement (taille dune page la position de deacutepart) nous laissons GTK+ faireen passant NULL

Cest un bon deacutebut mais estheacutetiquement on peut faire mieux mecircme sil nest pas utile davoir une barre de deacutefilementelle est quand mecircme afficheacutee On peut demander agrave GTK+ de les afficher que si cela est neacutecessaire

mainc gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC)

En fait nous avons de la chance car la classe GtkTextView fait partie des widget qui supporte de faccedilon native les barresde deacutefilement Comment le savoir Ce genre de widget possegravede une ou deux proprieacuteteacutes de type GtkAdjustment (unepour la barre verticale lautre pour la barre horizontale) Actuellement seulement trois classes en sont capables lesGtkTextView les GtkTreeView et les GtkLayout

Comment faire pour les autres widgets Il faut passer par une classe adaptateur GtkViewport afin de creacuteer lesGtkAdjustment

XI-C - Code source

chapitre11zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 34 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XII - Les menus

XII-A - Aperccedilu

Cliquez pour agrandir

XII-B - Creacuteation du menu

Pour simplifier nous avons utiliseacute des boutons pour permettre agrave lutilisateur de creacuteer un document ouvrir un fichierMais il est plus courant dutiliser un menu pour afficher ces options GTK+ propose trois maniegraveres de creacuteer un menu

bull GtkItemFactory cette meacutethode est obsolegravete depuis la version 24 de GTK+

bull GtkUIManager cest ce quon appel une usine agrave gaz pour en savoir plus vous pouvez vous reporter aututoriel Utilisation de GtkUIManager

bull GtkMenu cest ce widget que nous allons eacutetudier il permet de creacuteer un menu manuellement (agrave lopposeacute deGtkUIManager)

Un menu selon GTK+ est composeacute de plusieurs eacuteleacutements

bull GtkMenuBar la barre de menu elle-mecircme

bull GtkMenu la partie deacuteroulante qui contient les diffeacuterents eacuteleacutements

bull GtkMenuItem cest sur ce widget que lutilisateur clique pour lancer une action

Pour commencer faisons linventaire de ce que nous avons besoin

bull Un GtkMenuBar qui sert de base au menu

bull Un GtkMenu pour commencer nous nous aurons dun menu Fichier

bull Six GtkMenuItem pour remplacer nos six boutons

Commenccedilons par la creacuteation du menu nous mettons ce code dans un nouveau fichier dont seul la fonction menu_newsera accessible

menucGtkMenuBar menu_new (gpointer user_data) GtkWidget p_menu_bar = NULL

p_menu_bar = gtk_menu_bar_new () return GTK_MENU_BAR (p_menu_bar)

Le paramegravetre user_data nous servira lors de la connexion des callbacks (nous en avons besoin pour les fonctionscb_new et cb_open)

Ensuite nous allons creacuteer notre sous menu Fichier

menuc Menu Fichier

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 35 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

menuc GtkWidget p_menu = NULL GtkWidget p_menu_item = NULL

p_menu = gtk_menu_new () p_menu_item = gtk_menu_item_new_with_mnemonic (_Fichier) gtk_menu_item_set_submenu (GTK_MENU_ITEM (p_menu_item) p_menu) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu_bar) p_menu_item) return GTK_MENU_BAR (p_menu_bar)

Un sous menu est en fait un GtkMenuItem auquel on assigne un GtkMenu Il faut bien sucircr terminer la creacuteation dusous-menu en lajoutant agrave la barre de menu

Pour finir nous creacuteons les eacuteleacutements du menu les GtkItemMenu Il existe plusieurs types deacuteleacutements (comparableaux diffeacuterents types de bouton) pour commencer nous nutiliserons que le type de base Comme cette opeacuteration estreacutepeacutetitive nous allons creacuteer une fonction pour le faire

menucstatic void menu_item_new (GtkMenu p_menu const gchar title GCallback callback gpointer user_data) GtkWidget p_menu_item = NULL

p_menu_item = gtk_menu_item_new_with_mnemonic (title) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu) p_menu_item) g_signal_connect (G_OBJECT (p_menu_item) activate callback user_data)

Pour permettre agrave lutilisateur dacceacuteder aux diffeacuterents eacuteleacutements du menu agrave laide de la touche ltAltgt nous utilisonsdes mneacutemoniques par exemple pour quitter leacutediteur il suffit de faite Alt+F puis Q Et voici le code pour creacuteer nossix eacuteleacutements du menu

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau G_CALLBACK (cb_new) user_data) menu_item_new (GTK_MENU (p_menu) _Ouvrir G_CALLBACK (cb_open) user_data) menu_item_new (GTK_MENU (p_menu) _Enregistrer G_CALLBACK (cb_save) user_data) menu_item_new (GTK_MENU (p_menu) Enregistrer _sous G_CALLBACK (cb_saveas) user_data) menu_item_new (GTK_MENU (p_menu) _Fermer G_CALLBACK (cb_close) user_data) menu_item_new (GTK_MENU (p_menu) _Quitter G_CALLBACK (cb_quit) user_data)

Voilagrave notre menu est creacuteeacute il nous reste plus quagrave linteacutegrer agrave notre fenecirctre

mainc gtk_box_pack_start (GTK_BOX (p_main_box) GTK_WIDGET (menu_new (p_text_view)) FALSE FALSE 0)

Le problegraveme cest que nous avons besoin de passer le GtkTextView lors de la creacuteation du menu (qui est utiliseacute par lesfonctions cb_new et cb_open) or celui-ci est creacuteeacute apregraves le menu (puisque nous creacuteons les widgets dans lordre ougrave ilfaut les inteacutegrer agrave linterface (8) ) nous devons creacuteer le GtkTextView (seul lappel agrave gtk_text_view_new est deacuteplaceacute)

XII-C - Code source

chapitre12zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 36 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIII - Les barres doutils

XIII-A - Aperccedilu

Cliquez pour agrandir

XIII-B - Creacuteation dune barre doutils

La creacuteation dune barre doutils ressemble fort agrave celle dun menu en plus simple puisquil ny a pas de sous menu on creacutee notre barre doutils (gtk_toolbar_new) puis les eacuteleacutements de la barre pour cela on utilise des boutons(gtk_tool_button_new_from_stock) que lon inseacutere dans la barre (gtk_toolbar_insert) Pas conseacutequent notre fichierbarreoutilsc ressemble agrave menuc

barreoutilscinclude ltgtkgtkhgtinclude callbackhinclude barreoutilsh

static void toolbar_item_new (GtkToolbar const gchar GCallback gpointer)

GtkToolbar toolbar_new (gpointer user_data) GtkWidget p_toolbar = NULL

p_toolbar = gtk_toolbar_new () toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_NEW G_CALLBACK (cb_new) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_OPEN G_CALLBACK (cb_open) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE G_CALLBACK (cb_save) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE_AS G_CALLBACK (cb_saveas) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_CLOSE G_CALLBACK (cb_close) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_QUIT G_CALLBACK (cb_quit) user_data) return GTK_TOOLBAR (p_toolbar)

static void toolbar_item_new (GtkToolbar p_toolbar const gchar stock_id GCallback callback gpointer user_data) GtkToolItem p_tool_item = NULL

p_tool_item = gtk_tool_button_new_from_stock (stock_id) g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data) gtk_toolbar_insert (p_toolbar p_tool_item -1)

Le code nest pas complet car lorsque jexeacutecute le programme GTK+ affiche en plus des icocircnes le texte sous lesboutons Pour modifier cela il suffit dajouter une ligne de code

barreoutilsc gtk_toolbar_set_style (GTK_TOOLBAR (p_toolbar) GTK_TOOLBAR_ICONS)

Pourquoi gtk_tool_button_new_from_stock retourne un GtkToolItem et non un GtkWidgetcomme nous avons eacuteteacute habitueacute jusquagrave preacutesent Il sagit dune bizarrerie de GTK+ dontje ne connais pas la raison

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 37 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour anticiper un changement dinterface (dans GTK+ 30 peut ecirctre ) nous aurions pueacutecrire

Gtkwidget p_tool_item = NULL

p_tool_item = GTK_WIDGET (gtk_tool_button_new_from_stock (stock_id))g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data)gtk_toolbar_insert (p_toolbar GTK_TOOL_ITEM (p_tool_item) -1)

XIII-C - Code source

chapitre13zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 38 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIV - Les racourcis clavier

XIV-A - Aperccedilu

Cliquez pour agrandir

XIV-B - Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mneacutemoniques ces derniers permettent dacceacuteder agrave un eacuteleacutementseacutequentiellement alors que les raccourcis appellent une fonction si lutilisateur appuie simultaneacutement sur une ouplusieurs touches (geacuteneacuteralement de la forme ltModificateurgtTouche ougrave Modificateur repreacutesente les touches ShiftAlt et Control) Ce raccourci peut ecirctre attacheacute agrave un eacuteleacutement du menu mais ceci nest pas obligatoire

Les raccourcis sont regroupeacutes en groupe dans un GtkAccelGroup quil faut commencer par creacuteer

raccourciscinclude ltgtkgtkhgtinclude callbackhinclude raccourcish

GtkAccelGroup accel_group_new (gpointer user_data) GtkAccelGroup p_accel_group = NULL

p_accel_group = gtk_accel_group_new () return p_accel_group

Vous commencez agrave avoir lhabitude de cette organisation nous allons donc creacuteer une fonction qui va se chargerdajouter un raccourci au groupe

raccourciscstatic void accelerator_new (GtkAccelGroup p_accel_group const gchar accelerator const gchar accel_path GCallback callback gpointer user_data) guint key GdkModifierType mods GClosure closure = NULL

gtk_accelerator_parse (accelerator ampkey ampmods) closure = g_cclosure_new (callback user_data NULL) gtk_accel_group_connect (p_accel_group key mods GTK_ACCEL_VISIBLE closure) gtk_accel_map_add_entry (accel_path key mods)

La fonction gtk_accelerator_parse permet de deacutecomposer une chaicircne de caractegraveres de la forme ltControlgtF1 ouencore ltAltgtA en numeacutero de touche et modificateur

En plus des touches pour creacuteer un raccourci clavier nous avons besoin dune fonction agrave appeler lorsque lutilisateurappuie sur les touches speacutecifieacutees gtk_accel_group_connect attend une fonction du type GClosure regardons ladocumentation de gobject pour savoir agrave quoi cela correspond

typedef struct

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 33 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XI - Les barres de deacutefilement

XI-A - Aperccedilu

Cliquez pour agrandir

XI-B - Ajouter des barres de deacutefilement

Apregraves le dernier chapitre quelque peu laborieux voici une partie plus simple mais qui va rendre notre applicationplus pratique En effet si vous avez essayeacute douvrir un fichier de grande taille vous avez pu remarquer que pourpouvoir lire la fin du fichier il fallait utiliser les touches du clavier pas tregraves convivial

Pour rendre la navigation plus aiseacutee on utilise des barres de deacutefilement

mainc GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_box_pack_start (GTK_BOX (p_main_box) p_scrolled_window TRUE TRUE 0)

Creation de la zone de texte gtk_container_add (GTK_CONTAINER (p_scrolled_window) p_text_view)

Le constructeur de notre GtkScrolledWindow prend en argument deux GtkAdjustment qui permettent de deacutefinirdiffeacuterentes proprieacuteteacutes de la barre de deacutefilement (taille dune page la position de deacutepart) nous laissons GTK+ faireen passant NULL

Cest un bon deacutebut mais estheacutetiquement on peut faire mieux mecircme sil nest pas utile davoir une barre de deacutefilementelle est quand mecircme afficheacutee On peut demander agrave GTK+ de les afficher que si cela est neacutecessaire

mainc gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC)

En fait nous avons de la chance car la classe GtkTextView fait partie des widget qui supporte de faccedilon native les barresde deacutefilement Comment le savoir Ce genre de widget possegravede une ou deux proprieacuteteacutes de type GtkAdjustment (unepour la barre verticale lautre pour la barre horizontale) Actuellement seulement trois classes en sont capables lesGtkTextView les GtkTreeView et les GtkLayout

Comment faire pour les autres widgets Il faut passer par une classe adaptateur GtkViewport afin de creacuteer lesGtkAdjustment

XI-C - Code source

chapitre11zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 34 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XII - Les menus

XII-A - Aperccedilu

Cliquez pour agrandir

XII-B - Creacuteation du menu

Pour simplifier nous avons utiliseacute des boutons pour permettre agrave lutilisateur de creacuteer un document ouvrir un fichierMais il est plus courant dutiliser un menu pour afficher ces options GTK+ propose trois maniegraveres de creacuteer un menu

bull GtkItemFactory cette meacutethode est obsolegravete depuis la version 24 de GTK+

bull GtkUIManager cest ce quon appel une usine agrave gaz pour en savoir plus vous pouvez vous reporter aututoriel Utilisation de GtkUIManager

bull GtkMenu cest ce widget que nous allons eacutetudier il permet de creacuteer un menu manuellement (agrave lopposeacute deGtkUIManager)

Un menu selon GTK+ est composeacute de plusieurs eacuteleacutements

bull GtkMenuBar la barre de menu elle-mecircme

bull GtkMenu la partie deacuteroulante qui contient les diffeacuterents eacuteleacutements

bull GtkMenuItem cest sur ce widget que lutilisateur clique pour lancer une action

Pour commencer faisons linventaire de ce que nous avons besoin

bull Un GtkMenuBar qui sert de base au menu

bull Un GtkMenu pour commencer nous nous aurons dun menu Fichier

bull Six GtkMenuItem pour remplacer nos six boutons

Commenccedilons par la creacuteation du menu nous mettons ce code dans un nouveau fichier dont seul la fonction menu_newsera accessible

menucGtkMenuBar menu_new (gpointer user_data) GtkWidget p_menu_bar = NULL

p_menu_bar = gtk_menu_bar_new () return GTK_MENU_BAR (p_menu_bar)

Le paramegravetre user_data nous servira lors de la connexion des callbacks (nous en avons besoin pour les fonctionscb_new et cb_open)

Ensuite nous allons creacuteer notre sous menu Fichier

menuc Menu Fichier

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 35 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

menuc GtkWidget p_menu = NULL GtkWidget p_menu_item = NULL

p_menu = gtk_menu_new () p_menu_item = gtk_menu_item_new_with_mnemonic (_Fichier) gtk_menu_item_set_submenu (GTK_MENU_ITEM (p_menu_item) p_menu) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu_bar) p_menu_item) return GTK_MENU_BAR (p_menu_bar)

Un sous menu est en fait un GtkMenuItem auquel on assigne un GtkMenu Il faut bien sucircr terminer la creacuteation dusous-menu en lajoutant agrave la barre de menu

Pour finir nous creacuteons les eacuteleacutements du menu les GtkItemMenu Il existe plusieurs types deacuteleacutements (comparableaux diffeacuterents types de bouton) pour commencer nous nutiliserons que le type de base Comme cette opeacuteration estreacutepeacutetitive nous allons creacuteer une fonction pour le faire

menucstatic void menu_item_new (GtkMenu p_menu const gchar title GCallback callback gpointer user_data) GtkWidget p_menu_item = NULL

p_menu_item = gtk_menu_item_new_with_mnemonic (title) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu) p_menu_item) g_signal_connect (G_OBJECT (p_menu_item) activate callback user_data)

Pour permettre agrave lutilisateur dacceacuteder aux diffeacuterents eacuteleacutements du menu agrave laide de la touche ltAltgt nous utilisonsdes mneacutemoniques par exemple pour quitter leacutediteur il suffit de faite Alt+F puis Q Et voici le code pour creacuteer nossix eacuteleacutements du menu

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau G_CALLBACK (cb_new) user_data) menu_item_new (GTK_MENU (p_menu) _Ouvrir G_CALLBACK (cb_open) user_data) menu_item_new (GTK_MENU (p_menu) _Enregistrer G_CALLBACK (cb_save) user_data) menu_item_new (GTK_MENU (p_menu) Enregistrer _sous G_CALLBACK (cb_saveas) user_data) menu_item_new (GTK_MENU (p_menu) _Fermer G_CALLBACK (cb_close) user_data) menu_item_new (GTK_MENU (p_menu) _Quitter G_CALLBACK (cb_quit) user_data)

Voilagrave notre menu est creacuteeacute il nous reste plus quagrave linteacutegrer agrave notre fenecirctre

mainc gtk_box_pack_start (GTK_BOX (p_main_box) GTK_WIDGET (menu_new (p_text_view)) FALSE FALSE 0)

Le problegraveme cest que nous avons besoin de passer le GtkTextView lors de la creacuteation du menu (qui est utiliseacute par lesfonctions cb_new et cb_open) or celui-ci est creacuteeacute apregraves le menu (puisque nous creacuteons les widgets dans lordre ougrave ilfaut les inteacutegrer agrave linterface (8) ) nous devons creacuteer le GtkTextView (seul lappel agrave gtk_text_view_new est deacuteplaceacute)

XII-C - Code source

chapitre12zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 36 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIII - Les barres doutils

XIII-A - Aperccedilu

Cliquez pour agrandir

XIII-B - Creacuteation dune barre doutils

La creacuteation dune barre doutils ressemble fort agrave celle dun menu en plus simple puisquil ny a pas de sous menu on creacutee notre barre doutils (gtk_toolbar_new) puis les eacuteleacutements de la barre pour cela on utilise des boutons(gtk_tool_button_new_from_stock) que lon inseacutere dans la barre (gtk_toolbar_insert) Pas conseacutequent notre fichierbarreoutilsc ressemble agrave menuc

barreoutilscinclude ltgtkgtkhgtinclude callbackhinclude barreoutilsh

static void toolbar_item_new (GtkToolbar const gchar GCallback gpointer)

GtkToolbar toolbar_new (gpointer user_data) GtkWidget p_toolbar = NULL

p_toolbar = gtk_toolbar_new () toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_NEW G_CALLBACK (cb_new) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_OPEN G_CALLBACK (cb_open) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE G_CALLBACK (cb_save) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE_AS G_CALLBACK (cb_saveas) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_CLOSE G_CALLBACK (cb_close) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_QUIT G_CALLBACK (cb_quit) user_data) return GTK_TOOLBAR (p_toolbar)

static void toolbar_item_new (GtkToolbar p_toolbar const gchar stock_id GCallback callback gpointer user_data) GtkToolItem p_tool_item = NULL

p_tool_item = gtk_tool_button_new_from_stock (stock_id) g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data) gtk_toolbar_insert (p_toolbar p_tool_item -1)

Le code nest pas complet car lorsque jexeacutecute le programme GTK+ affiche en plus des icocircnes le texte sous lesboutons Pour modifier cela il suffit dajouter une ligne de code

barreoutilsc gtk_toolbar_set_style (GTK_TOOLBAR (p_toolbar) GTK_TOOLBAR_ICONS)

Pourquoi gtk_tool_button_new_from_stock retourne un GtkToolItem et non un GtkWidgetcomme nous avons eacuteteacute habitueacute jusquagrave preacutesent Il sagit dune bizarrerie de GTK+ dontje ne connais pas la raison

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 37 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour anticiper un changement dinterface (dans GTK+ 30 peut ecirctre ) nous aurions pueacutecrire

Gtkwidget p_tool_item = NULL

p_tool_item = GTK_WIDGET (gtk_tool_button_new_from_stock (stock_id))g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data)gtk_toolbar_insert (p_toolbar GTK_TOOL_ITEM (p_tool_item) -1)

XIII-C - Code source

chapitre13zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 38 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIV - Les racourcis clavier

XIV-A - Aperccedilu

Cliquez pour agrandir

XIV-B - Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mneacutemoniques ces derniers permettent dacceacuteder agrave un eacuteleacutementseacutequentiellement alors que les raccourcis appellent une fonction si lutilisateur appuie simultaneacutement sur une ouplusieurs touches (geacuteneacuteralement de la forme ltModificateurgtTouche ougrave Modificateur repreacutesente les touches ShiftAlt et Control) Ce raccourci peut ecirctre attacheacute agrave un eacuteleacutement du menu mais ceci nest pas obligatoire

Les raccourcis sont regroupeacutes en groupe dans un GtkAccelGroup quil faut commencer par creacuteer

raccourciscinclude ltgtkgtkhgtinclude callbackhinclude raccourcish

GtkAccelGroup accel_group_new (gpointer user_data) GtkAccelGroup p_accel_group = NULL

p_accel_group = gtk_accel_group_new () return p_accel_group

Vous commencez agrave avoir lhabitude de cette organisation nous allons donc creacuteer une fonction qui va se chargerdajouter un raccourci au groupe

raccourciscstatic void accelerator_new (GtkAccelGroup p_accel_group const gchar accelerator const gchar accel_path GCallback callback gpointer user_data) guint key GdkModifierType mods GClosure closure = NULL

gtk_accelerator_parse (accelerator ampkey ampmods) closure = g_cclosure_new (callback user_data NULL) gtk_accel_group_connect (p_accel_group key mods GTK_ACCEL_VISIBLE closure) gtk_accel_map_add_entry (accel_path key mods)

La fonction gtk_accelerator_parse permet de deacutecomposer une chaicircne de caractegraveres de la forme ltControlgtF1 ouencore ltAltgtA en numeacutero de touche et modificateur

En plus des touches pour creacuteer un raccourci clavier nous avons besoin dune fonction agrave appeler lorsque lutilisateurappuie sur les touches speacutecifieacutees gtk_accel_group_connect attend une fonction du type GClosure regardons ladocumentation de gobject pour savoir agrave quoi cela correspond

typedef struct

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 34 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XII - Les menus

XII-A - Aperccedilu

Cliquez pour agrandir

XII-B - Creacuteation du menu

Pour simplifier nous avons utiliseacute des boutons pour permettre agrave lutilisateur de creacuteer un document ouvrir un fichierMais il est plus courant dutiliser un menu pour afficher ces options GTK+ propose trois maniegraveres de creacuteer un menu

bull GtkItemFactory cette meacutethode est obsolegravete depuis la version 24 de GTK+

bull GtkUIManager cest ce quon appel une usine agrave gaz pour en savoir plus vous pouvez vous reporter aututoriel Utilisation de GtkUIManager

bull GtkMenu cest ce widget que nous allons eacutetudier il permet de creacuteer un menu manuellement (agrave lopposeacute deGtkUIManager)

Un menu selon GTK+ est composeacute de plusieurs eacuteleacutements

bull GtkMenuBar la barre de menu elle-mecircme

bull GtkMenu la partie deacuteroulante qui contient les diffeacuterents eacuteleacutements

bull GtkMenuItem cest sur ce widget que lutilisateur clique pour lancer une action

Pour commencer faisons linventaire de ce que nous avons besoin

bull Un GtkMenuBar qui sert de base au menu

bull Un GtkMenu pour commencer nous nous aurons dun menu Fichier

bull Six GtkMenuItem pour remplacer nos six boutons

Commenccedilons par la creacuteation du menu nous mettons ce code dans un nouveau fichier dont seul la fonction menu_newsera accessible

menucGtkMenuBar menu_new (gpointer user_data) GtkWidget p_menu_bar = NULL

p_menu_bar = gtk_menu_bar_new () return GTK_MENU_BAR (p_menu_bar)

Le paramegravetre user_data nous servira lors de la connexion des callbacks (nous en avons besoin pour les fonctionscb_new et cb_open)

Ensuite nous allons creacuteer notre sous menu Fichier

menuc Menu Fichier

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 35 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

menuc GtkWidget p_menu = NULL GtkWidget p_menu_item = NULL

p_menu = gtk_menu_new () p_menu_item = gtk_menu_item_new_with_mnemonic (_Fichier) gtk_menu_item_set_submenu (GTK_MENU_ITEM (p_menu_item) p_menu) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu_bar) p_menu_item) return GTK_MENU_BAR (p_menu_bar)

Un sous menu est en fait un GtkMenuItem auquel on assigne un GtkMenu Il faut bien sucircr terminer la creacuteation dusous-menu en lajoutant agrave la barre de menu

Pour finir nous creacuteons les eacuteleacutements du menu les GtkItemMenu Il existe plusieurs types deacuteleacutements (comparableaux diffeacuterents types de bouton) pour commencer nous nutiliserons que le type de base Comme cette opeacuteration estreacutepeacutetitive nous allons creacuteer une fonction pour le faire

menucstatic void menu_item_new (GtkMenu p_menu const gchar title GCallback callback gpointer user_data) GtkWidget p_menu_item = NULL

p_menu_item = gtk_menu_item_new_with_mnemonic (title) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu) p_menu_item) g_signal_connect (G_OBJECT (p_menu_item) activate callback user_data)

Pour permettre agrave lutilisateur dacceacuteder aux diffeacuterents eacuteleacutements du menu agrave laide de la touche ltAltgt nous utilisonsdes mneacutemoniques par exemple pour quitter leacutediteur il suffit de faite Alt+F puis Q Et voici le code pour creacuteer nossix eacuteleacutements du menu

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau G_CALLBACK (cb_new) user_data) menu_item_new (GTK_MENU (p_menu) _Ouvrir G_CALLBACK (cb_open) user_data) menu_item_new (GTK_MENU (p_menu) _Enregistrer G_CALLBACK (cb_save) user_data) menu_item_new (GTK_MENU (p_menu) Enregistrer _sous G_CALLBACK (cb_saveas) user_data) menu_item_new (GTK_MENU (p_menu) _Fermer G_CALLBACK (cb_close) user_data) menu_item_new (GTK_MENU (p_menu) _Quitter G_CALLBACK (cb_quit) user_data)

Voilagrave notre menu est creacuteeacute il nous reste plus quagrave linteacutegrer agrave notre fenecirctre

mainc gtk_box_pack_start (GTK_BOX (p_main_box) GTK_WIDGET (menu_new (p_text_view)) FALSE FALSE 0)

Le problegraveme cest que nous avons besoin de passer le GtkTextView lors de la creacuteation du menu (qui est utiliseacute par lesfonctions cb_new et cb_open) or celui-ci est creacuteeacute apregraves le menu (puisque nous creacuteons les widgets dans lordre ougrave ilfaut les inteacutegrer agrave linterface (8) ) nous devons creacuteer le GtkTextView (seul lappel agrave gtk_text_view_new est deacuteplaceacute)

XII-C - Code source

chapitre12zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 36 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIII - Les barres doutils

XIII-A - Aperccedilu

Cliquez pour agrandir

XIII-B - Creacuteation dune barre doutils

La creacuteation dune barre doutils ressemble fort agrave celle dun menu en plus simple puisquil ny a pas de sous menu on creacutee notre barre doutils (gtk_toolbar_new) puis les eacuteleacutements de la barre pour cela on utilise des boutons(gtk_tool_button_new_from_stock) que lon inseacutere dans la barre (gtk_toolbar_insert) Pas conseacutequent notre fichierbarreoutilsc ressemble agrave menuc

barreoutilscinclude ltgtkgtkhgtinclude callbackhinclude barreoutilsh

static void toolbar_item_new (GtkToolbar const gchar GCallback gpointer)

GtkToolbar toolbar_new (gpointer user_data) GtkWidget p_toolbar = NULL

p_toolbar = gtk_toolbar_new () toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_NEW G_CALLBACK (cb_new) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_OPEN G_CALLBACK (cb_open) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE G_CALLBACK (cb_save) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE_AS G_CALLBACK (cb_saveas) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_CLOSE G_CALLBACK (cb_close) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_QUIT G_CALLBACK (cb_quit) user_data) return GTK_TOOLBAR (p_toolbar)

static void toolbar_item_new (GtkToolbar p_toolbar const gchar stock_id GCallback callback gpointer user_data) GtkToolItem p_tool_item = NULL

p_tool_item = gtk_tool_button_new_from_stock (stock_id) g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data) gtk_toolbar_insert (p_toolbar p_tool_item -1)

Le code nest pas complet car lorsque jexeacutecute le programme GTK+ affiche en plus des icocircnes le texte sous lesboutons Pour modifier cela il suffit dajouter une ligne de code

barreoutilsc gtk_toolbar_set_style (GTK_TOOLBAR (p_toolbar) GTK_TOOLBAR_ICONS)

Pourquoi gtk_tool_button_new_from_stock retourne un GtkToolItem et non un GtkWidgetcomme nous avons eacuteteacute habitueacute jusquagrave preacutesent Il sagit dune bizarrerie de GTK+ dontje ne connais pas la raison

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 37 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour anticiper un changement dinterface (dans GTK+ 30 peut ecirctre ) nous aurions pueacutecrire

Gtkwidget p_tool_item = NULL

p_tool_item = GTK_WIDGET (gtk_tool_button_new_from_stock (stock_id))g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data)gtk_toolbar_insert (p_toolbar GTK_TOOL_ITEM (p_tool_item) -1)

XIII-C - Code source

chapitre13zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 38 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIV - Les racourcis clavier

XIV-A - Aperccedilu

Cliquez pour agrandir

XIV-B - Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mneacutemoniques ces derniers permettent dacceacuteder agrave un eacuteleacutementseacutequentiellement alors que les raccourcis appellent une fonction si lutilisateur appuie simultaneacutement sur une ouplusieurs touches (geacuteneacuteralement de la forme ltModificateurgtTouche ougrave Modificateur repreacutesente les touches ShiftAlt et Control) Ce raccourci peut ecirctre attacheacute agrave un eacuteleacutement du menu mais ceci nest pas obligatoire

Les raccourcis sont regroupeacutes en groupe dans un GtkAccelGroup quil faut commencer par creacuteer

raccourciscinclude ltgtkgtkhgtinclude callbackhinclude raccourcish

GtkAccelGroup accel_group_new (gpointer user_data) GtkAccelGroup p_accel_group = NULL

p_accel_group = gtk_accel_group_new () return p_accel_group

Vous commencez agrave avoir lhabitude de cette organisation nous allons donc creacuteer une fonction qui va se chargerdajouter un raccourci au groupe

raccourciscstatic void accelerator_new (GtkAccelGroup p_accel_group const gchar accelerator const gchar accel_path GCallback callback gpointer user_data) guint key GdkModifierType mods GClosure closure = NULL

gtk_accelerator_parse (accelerator ampkey ampmods) closure = g_cclosure_new (callback user_data NULL) gtk_accel_group_connect (p_accel_group key mods GTK_ACCEL_VISIBLE closure) gtk_accel_map_add_entry (accel_path key mods)

La fonction gtk_accelerator_parse permet de deacutecomposer une chaicircne de caractegraveres de la forme ltControlgtF1 ouencore ltAltgtA en numeacutero de touche et modificateur

En plus des touches pour creacuteer un raccourci clavier nous avons besoin dune fonction agrave appeler lorsque lutilisateurappuie sur les touches speacutecifieacutees gtk_accel_group_connect attend une fonction du type GClosure regardons ladocumentation de gobject pour savoir agrave quoi cela correspond

typedef struct

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 35 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

menuc GtkWidget p_menu = NULL GtkWidget p_menu_item = NULL

p_menu = gtk_menu_new () p_menu_item = gtk_menu_item_new_with_mnemonic (_Fichier) gtk_menu_item_set_submenu (GTK_MENU_ITEM (p_menu_item) p_menu) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu_bar) p_menu_item) return GTK_MENU_BAR (p_menu_bar)

Un sous menu est en fait un GtkMenuItem auquel on assigne un GtkMenu Il faut bien sucircr terminer la creacuteation dusous-menu en lajoutant agrave la barre de menu

Pour finir nous creacuteons les eacuteleacutements du menu les GtkItemMenu Il existe plusieurs types deacuteleacutements (comparableaux diffeacuterents types de bouton) pour commencer nous nutiliserons que le type de base Comme cette opeacuteration estreacutepeacutetitive nous allons creacuteer une fonction pour le faire

menucstatic void menu_item_new (GtkMenu p_menu const gchar title GCallback callback gpointer user_data) GtkWidget p_menu_item = NULL

p_menu_item = gtk_menu_item_new_with_mnemonic (title) gtk_menu_shell_append (GTK_MENU_SHELL (p_menu) p_menu_item) g_signal_connect (G_OBJECT (p_menu_item) activate callback user_data)

Pour permettre agrave lutilisateur dacceacuteder aux diffeacuterents eacuteleacutements du menu agrave laide de la touche ltAltgt nous utilisonsdes mneacutemoniques par exemple pour quitter leacutediteur il suffit de faite Alt+F puis Q Et voici le code pour creacuteer nossix eacuteleacutements du menu

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau G_CALLBACK (cb_new) user_data) menu_item_new (GTK_MENU (p_menu) _Ouvrir G_CALLBACK (cb_open) user_data) menu_item_new (GTK_MENU (p_menu) _Enregistrer G_CALLBACK (cb_save) user_data) menu_item_new (GTK_MENU (p_menu) Enregistrer _sous G_CALLBACK (cb_saveas) user_data) menu_item_new (GTK_MENU (p_menu) _Fermer G_CALLBACK (cb_close) user_data) menu_item_new (GTK_MENU (p_menu) _Quitter G_CALLBACK (cb_quit) user_data)

Voilagrave notre menu est creacuteeacute il nous reste plus quagrave linteacutegrer agrave notre fenecirctre

mainc gtk_box_pack_start (GTK_BOX (p_main_box) GTK_WIDGET (menu_new (p_text_view)) FALSE FALSE 0)

Le problegraveme cest que nous avons besoin de passer le GtkTextView lors de la creacuteation du menu (qui est utiliseacute par lesfonctions cb_new et cb_open) or celui-ci est creacuteeacute apregraves le menu (puisque nous creacuteons les widgets dans lordre ougrave ilfaut les inteacutegrer agrave linterface (8) ) nous devons creacuteer le GtkTextView (seul lappel agrave gtk_text_view_new est deacuteplaceacute)

XII-C - Code source

chapitre12zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 36 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIII - Les barres doutils

XIII-A - Aperccedilu

Cliquez pour agrandir

XIII-B - Creacuteation dune barre doutils

La creacuteation dune barre doutils ressemble fort agrave celle dun menu en plus simple puisquil ny a pas de sous menu on creacutee notre barre doutils (gtk_toolbar_new) puis les eacuteleacutements de la barre pour cela on utilise des boutons(gtk_tool_button_new_from_stock) que lon inseacutere dans la barre (gtk_toolbar_insert) Pas conseacutequent notre fichierbarreoutilsc ressemble agrave menuc

barreoutilscinclude ltgtkgtkhgtinclude callbackhinclude barreoutilsh

static void toolbar_item_new (GtkToolbar const gchar GCallback gpointer)

GtkToolbar toolbar_new (gpointer user_data) GtkWidget p_toolbar = NULL

p_toolbar = gtk_toolbar_new () toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_NEW G_CALLBACK (cb_new) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_OPEN G_CALLBACK (cb_open) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE G_CALLBACK (cb_save) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE_AS G_CALLBACK (cb_saveas) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_CLOSE G_CALLBACK (cb_close) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_QUIT G_CALLBACK (cb_quit) user_data) return GTK_TOOLBAR (p_toolbar)

static void toolbar_item_new (GtkToolbar p_toolbar const gchar stock_id GCallback callback gpointer user_data) GtkToolItem p_tool_item = NULL

p_tool_item = gtk_tool_button_new_from_stock (stock_id) g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data) gtk_toolbar_insert (p_toolbar p_tool_item -1)

Le code nest pas complet car lorsque jexeacutecute le programme GTK+ affiche en plus des icocircnes le texte sous lesboutons Pour modifier cela il suffit dajouter une ligne de code

barreoutilsc gtk_toolbar_set_style (GTK_TOOLBAR (p_toolbar) GTK_TOOLBAR_ICONS)

Pourquoi gtk_tool_button_new_from_stock retourne un GtkToolItem et non un GtkWidgetcomme nous avons eacuteteacute habitueacute jusquagrave preacutesent Il sagit dune bizarrerie de GTK+ dontje ne connais pas la raison

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 37 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour anticiper un changement dinterface (dans GTK+ 30 peut ecirctre ) nous aurions pueacutecrire

Gtkwidget p_tool_item = NULL

p_tool_item = GTK_WIDGET (gtk_tool_button_new_from_stock (stock_id))g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data)gtk_toolbar_insert (p_toolbar GTK_TOOL_ITEM (p_tool_item) -1)

XIII-C - Code source

chapitre13zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 38 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIV - Les racourcis clavier

XIV-A - Aperccedilu

Cliquez pour agrandir

XIV-B - Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mneacutemoniques ces derniers permettent dacceacuteder agrave un eacuteleacutementseacutequentiellement alors que les raccourcis appellent une fonction si lutilisateur appuie simultaneacutement sur une ouplusieurs touches (geacuteneacuteralement de la forme ltModificateurgtTouche ougrave Modificateur repreacutesente les touches ShiftAlt et Control) Ce raccourci peut ecirctre attacheacute agrave un eacuteleacutement du menu mais ceci nest pas obligatoire

Les raccourcis sont regroupeacutes en groupe dans un GtkAccelGroup quil faut commencer par creacuteer

raccourciscinclude ltgtkgtkhgtinclude callbackhinclude raccourcish

GtkAccelGroup accel_group_new (gpointer user_data) GtkAccelGroup p_accel_group = NULL

p_accel_group = gtk_accel_group_new () return p_accel_group

Vous commencez agrave avoir lhabitude de cette organisation nous allons donc creacuteer une fonction qui va se chargerdajouter un raccourci au groupe

raccourciscstatic void accelerator_new (GtkAccelGroup p_accel_group const gchar accelerator const gchar accel_path GCallback callback gpointer user_data) guint key GdkModifierType mods GClosure closure = NULL

gtk_accelerator_parse (accelerator ampkey ampmods) closure = g_cclosure_new (callback user_data NULL) gtk_accel_group_connect (p_accel_group key mods GTK_ACCEL_VISIBLE closure) gtk_accel_map_add_entry (accel_path key mods)

La fonction gtk_accelerator_parse permet de deacutecomposer une chaicircne de caractegraveres de la forme ltControlgtF1 ouencore ltAltgtA en numeacutero de touche et modificateur

En plus des touches pour creacuteer un raccourci clavier nous avons besoin dune fonction agrave appeler lorsque lutilisateurappuie sur les touches speacutecifieacutees gtk_accel_group_connect attend une fonction du type GClosure regardons ladocumentation de gobject pour savoir agrave quoi cela correspond

typedef struct

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 36 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIII - Les barres doutils

XIII-A - Aperccedilu

Cliquez pour agrandir

XIII-B - Creacuteation dune barre doutils

La creacuteation dune barre doutils ressemble fort agrave celle dun menu en plus simple puisquil ny a pas de sous menu on creacutee notre barre doutils (gtk_toolbar_new) puis les eacuteleacutements de la barre pour cela on utilise des boutons(gtk_tool_button_new_from_stock) que lon inseacutere dans la barre (gtk_toolbar_insert) Pas conseacutequent notre fichierbarreoutilsc ressemble agrave menuc

barreoutilscinclude ltgtkgtkhgtinclude callbackhinclude barreoutilsh

static void toolbar_item_new (GtkToolbar const gchar GCallback gpointer)

GtkToolbar toolbar_new (gpointer user_data) GtkWidget p_toolbar = NULL

p_toolbar = gtk_toolbar_new () toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_NEW G_CALLBACK (cb_new) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_OPEN G_CALLBACK (cb_open) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE G_CALLBACK (cb_save) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_SAVE_AS G_CALLBACK (cb_saveas) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_CLOSE G_CALLBACK (cb_close) user_data) toolbar_item_new (GTK_TOOLBAR (p_toolbar) GTK_STOCK_QUIT G_CALLBACK (cb_quit) user_data) return GTK_TOOLBAR (p_toolbar)

static void toolbar_item_new (GtkToolbar p_toolbar const gchar stock_id GCallback callback gpointer user_data) GtkToolItem p_tool_item = NULL

p_tool_item = gtk_tool_button_new_from_stock (stock_id) g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data) gtk_toolbar_insert (p_toolbar p_tool_item -1)

Le code nest pas complet car lorsque jexeacutecute le programme GTK+ affiche en plus des icocircnes le texte sous lesboutons Pour modifier cela il suffit dajouter une ligne de code

barreoutilsc gtk_toolbar_set_style (GTK_TOOLBAR (p_toolbar) GTK_TOOLBAR_ICONS)

Pourquoi gtk_tool_button_new_from_stock retourne un GtkToolItem et non un GtkWidgetcomme nous avons eacuteteacute habitueacute jusquagrave preacutesent Il sagit dune bizarrerie de GTK+ dontje ne connais pas la raison

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 37 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour anticiper un changement dinterface (dans GTK+ 30 peut ecirctre ) nous aurions pueacutecrire

Gtkwidget p_tool_item = NULL

p_tool_item = GTK_WIDGET (gtk_tool_button_new_from_stock (stock_id))g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data)gtk_toolbar_insert (p_toolbar GTK_TOOL_ITEM (p_tool_item) -1)

XIII-C - Code source

chapitre13zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 38 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIV - Les racourcis clavier

XIV-A - Aperccedilu

Cliquez pour agrandir

XIV-B - Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mneacutemoniques ces derniers permettent dacceacuteder agrave un eacuteleacutementseacutequentiellement alors que les raccourcis appellent une fonction si lutilisateur appuie simultaneacutement sur une ouplusieurs touches (geacuteneacuteralement de la forme ltModificateurgtTouche ougrave Modificateur repreacutesente les touches ShiftAlt et Control) Ce raccourci peut ecirctre attacheacute agrave un eacuteleacutement du menu mais ceci nest pas obligatoire

Les raccourcis sont regroupeacutes en groupe dans un GtkAccelGroup quil faut commencer par creacuteer

raccourciscinclude ltgtkgtkhgtinclude callbackhinclude raccourcish

GtkAccelGroup accel_group_new (gpointer user_data) GtkAccelGroup p_accel_group = NULL

p_accel_group = gtk_accel_group_new () return p_accel_group

Vous commencez agrave avoir lhabitude de cette organisation nous allons donc creacuteer une fonction qui va se chargerdajouter un raccourci au groupe

raccourciscstatic void accelerator_new (GtkAccelGroup p_accel_group const gchar accelerator const gchar accel_path GCallback callback gpointer user_data) guint key GdkModifierType mods GClosure closure = NULL

gtk_accelerator_parse (accelerator ampkey ampmods) closure = g_cclosure_new (callback user_data NULL) gtk_accel_group_connect (p_accel_group key mods GTK_ACCEL_VISIBLE closure) gtk_accel_map_add_entry (accel_path key mods)

La fonction gtk_accelerator_parse permet de deacutecomposer une chaicircne de caractegraveres de la forme ltControlgtF1 ouencore ltAltgtA en numeacutero de touche et modificateur

En plus des touches pour creacuteer un raccourci clavier nous avons besoin dune fonction agrave appeler lorsque lutilisateurappuie sur les touches speacutecifieacutees gtk_accel_group_connect attend une fonction du type GClosure regardons ladocumentation de gobject pour savoir agrave quoi cela correspond

typedef struct

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 37 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Pour anticiper un changement dinterface (dans GTK+ 30 peut ecirctre ) nous aurions pueacutecrire

Gtkwidget p_tool_item = NULL

p_tool_item = GTK_WIDGET (gtk_tool_button_new_from_stock (stock_id))g_signal_connect (G_OBJECT (p_tool_item) clicked callback user_data)gtk_toolbar_insert (p_toolbar GTK_TOOL_ITEM (p_tool_item) -1)

XIII-C - Code source

chapitre13zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 38 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIV - Les racourcis clavier

XIV-A - Aperccedilu

Cliquez pour agrandir

XIV-B - Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mneacutemoniques ces derniers permettent dacceacuteder agrave un eacuteleacutementseacutequentiellement alors que les raccourcis appellent une fonction si lutilisateur appuie simultaneacutement sur une ouplusieurs touches (geacuteneacuteralement de la forme ltModificateurgtTouche ougrave Modificateur repreacutesente les touches ShiftAlt et Control) Ce raccourci peut ecirctre attacheacute agrave un eacuteleacutement du menu mais ceci nest pas obligatoire

Les raccourcis sont regroupeacutes en groupe dans un GtkAccelGroup quil faut commencer par creacuteer

raccourciscinclude ltgtkgtkhgtinclude callbackhinclude raccourcish

GtkAccelGroup accel_group_new (gpointer user_data) GtkAccelGroup p_accel_group = NULL

p_accel_group = gtk_accel_group_new () return p_accel_group

Vous commencez agrave avoir lhabitude de cette organisation nous allons donc creacuteer une fonction qui va se chargerdajouter un raccourci au groupe

raccourciscstatic void accelerator_new (GtkAccelGroup p_accel_group const gchar accelerator const gchar accel_path GCallback callback gpointer user_data) guint key GdkModifierType mods GClosure closure = NULL

gtk_accelerator_parse (accelerator ampkey ampmods) closure = g_cclosure_new (callback user_data NULL) gtk_accel_group_connect (p_accel_group key mods GTK_ACCEL_VISIBLE closure) gtk_accel_map_add_entry (accel_path key mods)

La fonction gtk_accelerator_parse permet de deacutecomposer une chaicircne de caractegraveres de la forme ltControlgtF1 ouencore ltAltgtA en numeacutero de touche et modificateur

En plus des touches pour creacuteer un raccourci clavier nous avons besoin dune fonction agrave appeler lorsque lutilisateurappuie sur les touches speacutecifieacutees gtk_accel_group_connect attend une fonction du type GClosure regardons ladocumentation de gobject pour savoir agrave quoi cela correspond

typedef struct

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 38 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIV - Les racourcis clavier

XIV-A - Aperccedilu

Cliquez pour agrandir

XIV-B - Mise en place des raccourcis clavier

Il ne faut pas confondre les raccourcis clavier et les mneacutemoniques ces derniers permettent dacceacuteder agrave un eacuteleacutementseacutequentiellement alors que les raccourcis appellent une fonction si lutilisateur appuie simultaneacutement sur une ouplusieurs touches (geacuteneacuteralement de la forme ltModificateurgtTouche ougrave Modificateur repreacutesente les touches ShiftAlt et Control) Ce raccourci peut ecirctre attacheacute agrave un eacuteleacutement du menu mais ceci nest pas obligatoire

Les raccourcis sont regroupeacutes en groupe dans un GtkAccelGroup quil faut commencer par creacuteer

raccourciscinclude ltgtkgtkhgtinclude callbackhinclude raccourcish

GtkAccelGroup accel_group_new (gpointer user_data) GtkAccelGroup p_accel_group = NULL

p_accel_group = gtk_accel_group_new () return p_accel_group

Vous commencez agrave avoir lhabitude de cette organisation nous allons donc creacuteer une fonction qui va se chargerdajouter un raccourci au groupe

raccourciscstatic void accelerator_new (GtkAccelGroup p_accel_group const gchar accelerator const gchar accel_path GCallback callback gpointer user_data) guint key GdkModifierType mods GClosure closure = NULL

gtk_accelerator_parse (accelerator ampkey ampmods) closure = g_cclosure_new (callback user_data NULL) gtk_accel_group_connect (p_accel_group key mods GTK_ACCEL_VISIBLE closure) gtk_accel_map_add_entry (accel_path key mods)

La fonction gtk_accelerator_parse permet de deacutecomposer une chaicircne de caractegraveres de la forme ltControlgtF1 ouencore ltAltgtA en numeacutero de touche et modificateur

En plus des touches pour creacuteer un raccourci clavier nous avons besoin dune fonction agrave appeler lorsque lutilisateurappuie sur les touches speacutecifieacutees gtk_accel_group_connect attend une fonction du type GClosure regardons ladocumentation de gobject pour savoir agrave quoi cela correspond

typedef struct

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 39 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GClosure

Bon pas tregraves instructif ( Heureusement en regardant le constructeur de la classe GClosure on retombe sur deschoses connues

GClosure g_cclosure_new (GCallback callback_func gpointer user_data GClosureNotify destroy_data)

Le dernier paramegravetre est une fonction qui sera appeleacutee pour deacutetruire lobjet user_data lorsquil ne sera plus utiliseacute

Voilagrave nous pouvons deacutejagrave connecter le raccourci clavier agrave notre fonction callback

Pour finir pour associer un eacuteleacutement du menu agrave un raccourci clavier nous avons besoin de lajouter agrave la carte desraccourcis cette carte est unique et speacutecifique agrave chaque application

void gtk_accel_map_add_entry (const gchar accel_path guint accel_key GdkModifierType accel_mods)

Il nous manque juste le paramegravetre accel_path Il sagit comme son nom le laisse penser dun chemin pour notreraccourci Ce chemin est semblable agrave un chemin de fichier ltWINDOWTYPEgtCategory1Category2Actionougrave WINDOWTYPE est un identifiant speacutecifique agrave chaque application pour notre application nous utiliseronsEditeurGTK ensuite la documentation de GTK+ conseille pour les eacuteleacutements du menu dutiliser son chemin parexemple pour leacuteleacutement Nouveau FichierNouveau ce qui nous donne ltEditeurGTKgtFichierNouveau Commeil va ecirctre neacutecessaire de reprendre ces chemins lors de la creacuteation des eacuteleacutements du menu il est preacutefeacuterable den fairedes constantes

raccourcishdefine ACCEL_PATH_NEW ltEditeurGTKgtFichierNouveaudefine ACCEL_PATH_OPEN ltEditeurGTKgtFichierOuvrirdefine ACCEL_PATH_SAVE ltEditeurGTKgtFichierEnregistrerdefine ACCEL_PATH_SAVEAS ltEditeurGTKgtFichierEnregistrer sousdefine ACCEL_PATH_CLOSE ltEditeurGTKgtFichierFermerdefine ACCEL_PATH_QUIT ltEditeurGTKgtFichierQuitter

Avant de creacuteer nos raccourcis il faut reacutegler un problegraveme (sur ce point je trouve que GTK+ est mal fait) en effet il estpreacuteciseacute que la fonction callback pour les raccourcis doit avoir la signature suivante

gboolean (GtkAccelGroupActivate) (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier)

Alors que nous avons des fonctions de la forme

void callback (GtkWidget p_widget gpointer user_data)

On est donc obligeacute de creacuteer des fonctions de type GtkAccelGroupActivate qui vont se charger dappeler nos fonctionscallback

raccourciscstatic gboolean accel_new (GtkAccelGroup accel_group GObject acceleratable guint keyval GdkModifierType modifier gpointer user_data) cb_new (NULL user_data) return TRUE

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 40 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Notre fonction na pas la mecircme signature que les GtkAccelGroupActivate puisqueg_cclosure_new preacutecise quil appelle la fonction callback ainsi creacuteeacutee avec user_datacomme dernier paramegravetre

Maintenant que le problegraveme est reacutesolu creacuteons nos raccourcis

raccourcisc accelerator_new (p_accel_group ltControlgtN ACCEL_PATH_NEW G_CALLBACK (accel_new) user_data) accelerator_new (p_accel_group ltControlgtO ACCEL_PATH_OPEN G_CALLBACK (accel_open) user_data) accelerator_new (p_accel_group ltControlgtS ACCEL_PATH_SAVE G_CALLBACK (accel_save) user_data) accelerator_new (p_accel_group ltControlgtltShiftgtS ACCEL_PATH_SAVEAS G_CALLBACK (accel_saveas) user_data) accelerator_new (p_accel_group ltControlgtW ACCEL_PATH_CLOSE G_CALLBACK (accel_close) user_data) accelerator_new (p_accel_group ltControlgtQ ACCEL_PATH_QUIT G_CALLBACK (accel_quit) user_data)

Pour finir il faut ajouter le GtkAccelGroup agrave notre fenecirctre principale

raccourcisc gtk_window_add_accel_group (docsp_main_window p_accel_group)

Voilagrave nous en avons fini avec ce fichier maintenant il faut revenir agrave menuc pour associer les raccouris aux eacuteleacutementsdu menu Il nous suffit de modifier notre constructeur de GtkMenuItem pour quil prenne en argument le accel_path

menucstatic void menu_item_new (GtkMenu p_menu const gchar title const gchar accel_path GCallback callback gpointer user_data) gtk_menu_item_set_accel_path (GTK_MENU_ITEM (p_menu_item) accel_path)

Et dutiliser nos constantes lors de lappel agrave la fonction meni_item_new

menuc menu_item_new (GTK_MENU (p_menu) _Nouveau ACCEL_PATH_NEW G_CALLBACK (cb_new) user_data)

XIV-C - Code source

chapitre14zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 41 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XV - Messages derreur

XV-A - Aperccedilu

Cliquez pour agrandir

XV-B - Ameacutelioration de nos fonctions daffichage derreur

Jusquagrave preacutesent les messages derreurs eacutetaient afficheacutes agrave laide de la fonction printf mais cela oblige lutilisateur agravelancer le programme dans une console pas tregraves conviviale Encore une fois GTK+ vient agrave notre secours en proposantune classe GtkMessageDialog qui nous permet dafficher un message simplement sans avoir agrave creacuteer une boicircte dedialogue en partant de zeacutero

Voici la fonction qui nous permet de creacuteer notre boicircte de dialogue

GtkWidget gtk_message_dialog_new (GtkWindow parent GtkDialogFlags flags GtkMessageType type GtkButtonsType buttons const gchar message_format )

Donc nous avons besoin de notre fenecirctre principale pour cela il suffit dinclure documenth comme lutilisateurdoit dabord valider notre message avant de continuer agrave utiliser leacutediteur nous allons la rendre modale gracircceagrave la constante GTK_DIALOG_MODAL Ensuite vient le type de message cela va deacutependre de la fonctionappeleacutee (GTK_MESSAGE_INFO GTK_MESSAGE_WARNING ou GTK_MESSAGE_ERROR) Le seul bouton dontlutilisateur a besoin est le bouton Ok pour fermer la boicircte de dialogue (GTK_BUTTONS_OK) et pour finir la fonctionattend le message agrave afficher (sous la mecircme forme que la fonction printf)

Comme seul le type de message et le message va changer selon la fonction print_ appeleacutee une nouvelle fonctionest la bienvenue

errorcstatic void print_message (GtkMessageType type const gchar format va_list va) gchar message = NULL GtkWidget p_dialog = NULL

message = g_strdup_vprintf (format va) p_dialog = gtk_message_dialog_new (docsp_main_window GTK_DIALOG_MODAL type GTK_BUTTONS_OK message) g_free (message) message = NULL gtk_dialog_run (GTK_DIALOG (p_dialog)) gtk_widget_destroy (p_dialog)

Les fonctions de la famille de g_strdup_printf sont extrecircmement inteacuteressantes puisquelles permettent de creacuteerune nouvelle chaicircne de caractegraveres en utilisant la puissance des fonctions de la famille de printf (Voici un exempledimpleacutementation de ce genre de fonction Creacuteer une chaicircne de caractegraveres formateacutee)

Il nous reste plus quagrave modifier nos trois fonctions daffichage de message voici lexemple pour print_info

errorcvoid print_info (char format ) va_list va

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 42 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

errorc

va_start (va format) print_message (GTK_MESSAGE_INFO format va)

En C99 avec les macro agrave nombres variables nous pourrions remplacer nos fonctions pardes macro

define print_info(chat format ) print_message (GTK_MESSAGE_INFO (format) __VA_ARGS__)

XV-C - Code source

chapitre15zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 43 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVI - Ouvrir plusieurs fichiers en mecircme temps

XVI-A - Aperccedilu

Cliquez pour agrandir

XVI-B - Mise en place des onglets

Actuellement nous ne pouvons ouvrir quun seul fichier agrave la fois Les eacutediteurs de texte avanceacutes proposentgeacuteneacuteralement la possibiliteacute douvrir plusieurs documents simultaneacutement gracircce agrave un systegraveme donglets Cest ce quenous allons mettre en place gracircce au widget GtkNotebook

A la place du GtkTextView nous creacuteons un GtkNotebook et comme nous allons avoir besoin de modifier de widget(ajoutsuppression de pages) nous gardons un pointeur dessus dans notre structure globale

mainc Creation de la page donglets GtkWidget p_notebook = NULL

p_notebook = gtk_notebook_new () gtk_container_add (GTK_CONTAINER (p_main_box) p_notebook) docsp_notebook = GTK_NOTEBOOK (p_notebook)

Donc agrave louverture de leacutediteur aucun onglet est ouvert ils seront ajouteacutes lorsque lutilisateur creacutee un document ouen ouvre un Par chance (ou gracircce agrave lingeacuteniositeacute de lauteur de ce document je vous laisse choisir D) lajout dunenouvelle page se fait uniquement dans la fonction cb_new Nous avons anticipeacute la mise en place donglet au deacutebutde ce tutoriel en creacuteant la structure docs_t dont seul le champs actif eacutetait utiliseacute maintenant il faut ajouter chaquedocument ouvert agrave la GList

callbackcvoid cb_new (GtkWidget p_widget gpointer user_data) document_t nouveau = NULL

nouveau = g_malloc (sizeof (nouveau)) nouveau-gtchemin = NULL Le document vient detre ouvert il nest donc pas modifie nouveau-gtsauve = TRUE docstous = g_list_append (docstous nouveau) gint index = 0 GtkWidget p_scrolled_window = NULL

p_scrolled_window = gtk_scrolled_window_new (NULL NULL) gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (p_scrolled_window) GTK_POLICY_AUTOMATIC GTK_POLICY_AUTOMATIC) nouveau-gtp_text_view = GTK_TEXT_VIEW (gtk_text_view_new ()) GtkTextBuffer p_buffer = NULL

p_buffer = gtk_text_view_get_buffer (nouveau-gtp_text_view) g_signal_connect (G_OBJECT (p_buffer) changed G_CALLBACK (cb_modifie) NULL) gtk_container_add (GTK_CONTAINER (p_scrolled_window) GTK_WIDGET (nouveau-gtp_text_view))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 44 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc index = gtk_notebook_append_page (docsp_notebook p_scrolled_window GTK_WIDGET (gtk_label_new (Nouveau document))) gtk_widget_show_all (p_scrolled_window) gtk_notebook_set_current_page (docsp_notebook index)

parametres inutilises (void)p_widget (void)user_data

Premiegravere chose inteacuteressante il nest plus neacutecessaire de fermer le document pour en ouvrir un autre Ensuite plutocirctque de modifier le champ actif on creacutee un nouveau document que lon ajoute agrave la GList Le GtkTextView est creacuteeacutecomme preacuteceacutedemment mis agrave part quil est ajouteacute agrave un nouvel onglet que lon creacutee gracircce agrave la fonction

gint gtk_notebook_append_page (GtkNotebook notebook GtkWidget child GtkWidget tab_label)

Qui a besoin du widget enfant (il sagit du GtkScrolledWindow contenant le GtkTextView) et dun second widget quisera afficheacute dans longlet (nous laissons GTK+ mettre un texte par deacutefaut nous verrons plus loin comment ameacuteliorercela)

Une fois longlet creacuteeacute gtk_notebook_append_page nous retourne la position de la nouvelle page creacuteeacutee qui va nousservir agrave rendre la page active gracircce agrave la fonction

void gtk_notebook_set_current_page (GtkNotebook notebook gint page_num)

XVI-C - Changement de page

Pour pouvoir mettre agrave jour le document actif lorsque lutilisateur navigue entre les diffeacuterents onglets il suffitdintercepter le signal switch-page

maincg_signal_connect (G_OBJECT (p_notebook) switch-page G_CALLBACK (cb_page_change) NULL)

La fonction cb_page_change reacutecupeacutere la position de la page courante et fait pointer actif vers la structure document_tcorrespondante stockeacutee dans la GList

callbackcvoid cb_page_change (GtkNotebook notebook GtkNotebookPage page guint page_num gpointer user_data) docsactif = g_list_nth_data (docstous page_num)

parametres inutilises (void)notebook (void)user_data

Comme GTK+ fait bien les choses la fonction gtk_notebook_set_current_page que nous appelons lors de la creacuteationdun document eacutemet ce signal donc pas besoin de recopier ce code dans cb_new

XVI-D - Fermer un onglet

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 45 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

La derniegravere fonction qui neacutecessite quelques modifications est cb_close il faut maintenant supprimer le documentde la GList libeacuterer la meacutemoire et supprimer longlet

callbackcvoid cb_close (GtkWidget p_widget gpointer user_data) Avant de fermer il faut verifier quun document a bien ete ouvert if (docsactif) docstous = g_list_remove (docstous docsactif) g_free (docsactif-gtchemin) docsactif-gtchemin = NULL g_free (docsactif) docsactif = NULL gtk_notebook_remove_page (docsp_notebook gtk_notebook_get_current_page (docsp_notebook)) if (gtk_notebook_get_n_pages (docsp_notebook) gt 0) docsactif = g_list_nth_data (docstous gtk_notebook_get_current_page (docsp_notebook)) else docsactif = NULL else print_warning (Aucun document ouvert)

parametres inutilises (void)p_widget (void)user_data

Il reste plus quagrave supprimer lappel agrave la fonction gtk_widget_set_sensitive dans la fonction open_file maintenantdevenu inutile

Bizarrement la suppression dun onglet neacutemet pas de signal switch-page nous devonsle faire manuellement

XVI-E - Fermer tous les onglets

Maintenant que nous pouvons ouvrir plusieurs documents en mecircme temps il est neacutecessaire de les fermer touslorsquon quitte le programme

Jai essayeacute plusieurs meacutethodes avant de trouver une meacutethode convenable Contrairement agrave ce que lon pourraitpenser il ne suffit pas dutiliser la fonction g_list_foreach qui permet de parcourir lensemble dune liste chaicircneacutee etde fermer les documents un agrave un Le problegraveme vient des documents non sauvegardeacutes puisque lutilisateur peut agrave toutmoment deacutecider dannuler lenregistrement dun document ce qui nous oblige agrave annuler la fermeture de lapplication

Le principe que jai choisi dadopter consiste agrave boucler tant que tous les documents ne sont pas fermeacutes (dans cecas docsactif vaut NULL) et de demander la fermeture du premier onglet (puisque le numeacutero du dernier change agravechaque iteacuteration) Si lutilisateur choisit dannuler lenregistrement dans ce cas longlet nest pas fermeacute et le nombrede documents ouverts est le mecircme avant et apregraves lappel agrave cb_close nous mettons alors fin agrave la boucle et signalonslannulation en retournant FALSE si tous les documents ont bien eacuteteacute fermeacutes la fonction renvoit TRUE

static gboolean close_all (void)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 46 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

gboolean ret = TRUE

while (docsactif) gint tmp = gtk_notebook_get_n_pages (docsp_notebook)

gtk_notebook_set_current_page (docsp_notebook 0) cb_close (NULL NULL) if (gtk_notebook_get_n_pages (docsp_notebook) gt= tmp) ret = FALSE break return ret

Et la fonction cb_quit devient

void cb_quit (GtkWidget p_widget gpointer user_data) if (close_all ()) g_free (docsdir_name) docsdir_name = NULL gtk_main_quit()

parametres inutilises (void)p_widget (void)user_data

XVI-F - Modifier le titre de la page

Pour plus destheacutetisme nous allons modifier les titres des onglets Pour les nouveaux documents nous afficheronsun texte par deacutefaut (Nouveau document par exemple) une fois enregistreacute nous afficherons le nom du fichier (sansle chemin pour faire court) Et lorsque le document a eacuteteacute modifieacute depuis la derniegravere sauvegarde nous ajouteronsun petit asteacuterisque agrave cocircteacute du titre

Les bases eacutetant poseacutees nous allons commencer par construire notre titre

callbackcstatic void set_title (void) if (docsactif) gchar title = NULL gchar tmp = NULL

if (docsactif-gtchemin) tmp = g_path_get_basename (docsactif-gtchemin) else tmp = g_strdup (Nouveau document) if (docsactif-gtsauve) title = g_strdup (tmp)

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 47 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc else title = g_strdup_printf (s tmp) g_free (tmp) tmp = NULL g_free (title) title = NULL

Quelques lignes de code simplifieacutees gracircce aux fonctions de la glib Nous obtenons donc notre titre dans la variabletitre qui nous reste plus quagrave inseacuterer dans longlet

callbackc gint index = 0 GtkWidget p_child = NULL GtkLabel p_label = NULL

index = gtk_notebook_get_current_page (docsp_notebook) p_child = gtk_notebook_get_nth_page (docsp_notebook index) p_label = GTK_LABEL (gtk_notebook_get_tab_label (docsp_notebook p_child)) gtk_label_set_text (p_label title)

Cela peut paraicirctre bizarre mais modifier le titre dun onglet nest pas trivial il faut commencer par reacutecupeacuterer le numeacuterode la page en cours pour obtenir le widget qui est afficheacute dans longlet (car nous sommes libre de mettre le widgetde notre choix) et comme dans notre cas cest un simple GtkLabel on utilise la fonction gtk_label_set_text pourmettre agrave jour le titre Pour finir il faut faire appel agrave la fonction set_title lorsquon creacutee ouvre sauvegarde ou modifieun document cest agrave dire respectivement dans les fonctions cb_new open_file cb_save et cb_modifie

Et voilagrave cest tout Moyennant quelques efforts de reacuteflexion au deacutebut le changement entre un eacutediteur simple etmulti-documents est extrecircmement simple et a mecircme simplifieacute notre code par exemple pour la creacuteation du menunous navons plus besoin du paramegravetre user_data (pour simplifier et au cas ougrave nous en aurions de nouveau besoinnous passons la valeur NULL)

XVI-G - Code source

chapitre16zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 48 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII - Afficher larborescence du disque

XVII-A - Aperccedilu

Cliquez pour agrandir

XVII-B - Preacuteparons le terrain

Nous allons avoir besoin dajouter un GtkTreeView agrave cocircteacute du GtkTextView La premiegravere ideacutee qui vient agrave lesprit estde creacuteer un GtkHBox dans la boicircte principale Mais pour varier les plaisirs nous allons utiliser un nouveau type deconteneur les GtkPaned ils permettent de seacuteparer une zone en deux parties seacutepareacutees par une barre mobile

Nous creacuteons donc un GtkHPaned (la seacuteparation se fait dans le sens horizontal agrave lopposeacute des GtkVPaned)

mainc GtkWidget p_hpaned = NULL

p_hpaned = gtk_hpaned_new () gtk_box_pack_start (GTK_BOX (p_main_box) p_hpaned TRUE TRUE 0)

Et plutocirct que dafficher la GtkNotebook dans la boicircte principale nous laffichons maintenant dans la seconde partiede notre nouveau containeur

mainc gtk_paned_add2 (GTK_PANED (p_hpaned) p_notebook)

XVII-C - Creacuteation dun GtkTreeView

Les GtkTreeView sont sucircrement les widgets les plus difficiles agrave maicirctriser Ceci est due au fait que la gestion ducontenu et de laffichage est seacutepareacute en deux widgets et quil est possible dafficher une simple liste ou un arbre

bull GtkListStore et GtkTreeStore pour stocker respectivement le contenu dune liste et dun arbre

bull GtkTreeView pour afficher le contenu des GtkStore

Nous avons donc le choix entre afficher le contenu du reacutepertoire courant ou afficher toute larborescence du disqueNous opterons pour la premiegravere solution car lister tout le contenu du disque serait bien trop long (surtout de nosjours ougrave un disque dur fait plusieurs dizaines de GO) Mais pour ne pas se limiter au reacutepertoire ougrave se trouve notreprogramme (ce qui serait gecircnant sil se trouve dans usrbin) nous allons aussi lister les reacutepertoires preacutesents pourpermettre agrave lutilisateur de naviguer dans larborescence

Pour reacutesumer nos objectifs nous voulons creacuteer un GtkTreeView qui affichera un GtkListStore contenant le nom desfichiers et dossiers preacutesents dans un reacutepertoire donneacute Lorsque lutilisateur clique sur un nom repreacutesentant un fichieron louvre sil sagit dun dossier on reacuteactualise le GtkListStore avec le contenu de ce nouveau reacutepertoire

Y a plus qua

XVII-C-1 - Creacuteation du magasin

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 49 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

mainc p_list_store = gtk_list_store_new (2 GDK_TYPE_PIXBUF G_TYPE_STRING) docsp_list_store = p_list_store docsdir_name = g_strdup (g_get_home_dir ()) dir_list ()

Qui a oseacute dire quil sagissait de la partie la plus difficile Vous laurez compris tout le code se trouve dans la fonctiondir_list que nous verrons plus tard Pour commencer on construit notre GtkListStore en preacutecisant le nombre decolonnes souhaiteacute suivi de leurs types Nous souhaitons deux colonnes la premiegravere contiendra un GdkPixbuf (uneimage) pour diffeacuterencier les dossiers des fichiers et la seconde le nom du fichier

Ensuite nous sauvegardons notre GtkListStrore et le chemin du dossier agrave afficher (la fonction g_get_home_dir nouspermet de connaicirctre le dossier de lutilisateur) dans notre structure globale car nous en avons besoin dans plusieursfonctions callback par la suite

Maintenant passons au remplissage du magasin Comme nous serons ameneacutes agrave rafraicircchir le contenu de ce dernieron commence par le vider

callbackc gtk_list_store_clear (docsp_list_store)

Pour lister le contenu du reacutepertoire nous allons utiliser la glib Apregraves avoir ouvert le reacutepertoire il nous suffit dappeler lafonction g_dir_read_name qui agrave chaque appel nous renvoie le fichier (9) suivant puis NULL lorsque tout le reacutepertoirea eacuteteacute parcouru

callbackcvoid dir_list (void) GDir dir = NULL

dir = g_dir_open (docsdir_name 0 NULL) if (dir) const gchar read_name = NULL

while ((read_name = g_dir_read_name (dir))) g_dir_close (dir) dir = NULL

Pour chaque fichier il faut commencer par reconstruire son chemin complet

callbackc gchar file_name = NULL

file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name read_name NULL)

La fonction g_build_path concategravene lensemble de ses arguments sauf le premier qui est le seacuteparateur utiliseacuteMaintenant que nous avons notre nom complet nous pouvons tester si notre fichiers est un dossier ou pas

callbackc GdkPixbuf p_file_image = NULL

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 50 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

callbackc if (g_file_test (file_name G_FILE_TEST_IS_DIR)) p_file_image = gdk_pixbuf_new_from_file (dossierpng NULL) else p_file_image = gdk_pixbuf_new_from_file (fichierpng NULL)

La fonction permet de tester diffeacuterentes proprieacuteteacutes relatives aux fichiers

typedef enum G_FILE_TEST_IS_REGULAR = 1 ltlt 0 TRUE si le fichier est un fichier standard (ni un lien symbolique ni un dossier) G_FILE_TEST_IS_SYMLINK = 1 ltlt 1 TRUE si le fichier est un lien symbolique G_FILE_TEST_IS_DIR = 1 ltlt 2 TRUE si le fichier est un dossier G_FILE_TEST_IS_EXECUTABLE = 1 ltlt 3 TRUE si le fichier est un executable G_FILE_TEST_EXISTS = 1 ltlt 4 TRUE si le fichier existe GFileTest

Donc selon le type de fichier nous chargeons limage approprieacute dans un GdkPixbuf Le second paramegravetre de lafonction gdk_pixbuf_new_from_file permet de reacutecupeacuterer plus dinformation lorsquune erreur survient

Pour finir il nous reste plus quagrave ajouter une nouvelle colonne dans le GtkListStore Ceci se reacutealise en deux eacutetapesLa premiegravere consiste agrave ajouter une colonne

callbackc GtkTreeIter iter gtk_list_store_append (docsp_list_store ampiter)

Comme pour le GtkTextView nous avons besoin dun iteacuterateur qui va nous permettre de remplir cette colonne agravelaide dune seconde fonction

callbackc gtk_list_store_set (docsp_list_store ampiter 0 p_file_image 1 read_name -1)

Le premier paramegravetre est bien sucircr notre magasin ensuite il sagit de liteacuterateur symbolisant la colonne nouvellementcreacuteeacutee et enfin des couples numeacutero de colonnedonneacutee qui doivent correspondre au nombre et type preacuteciseacute lors dela creacuteation du GkListStore

En plus de cela nous ajoutons aussi un dossier puisque la fonction g_dir_read_name ne le liste pas pourpermettre agrave lutilisateur de remonter dans larborescence

XVII-C-2 - Affichage de larborescence

Voilagrave notre GtkListStore est precirct Maintenant il nous faut associer ce dernier au GtkTreeView Ceci na besoin decirctrefait quune seule fois lors de la creacuteation du widget

mainc p_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (p_list_store))

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 51 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

GtkTreeModel est une interface utiliseacutee par GtkTreeView la classe GtkListStore impleacutementant cette interface il estpossible de reacutealiser un transtypage

Si lhistoire sarrecircterai lagrave creacuteer un GtkTextView sera plutocirct simple Heacutelas nous devons creacuteer les colonnes dans leGtkTextView et les faire correspondre agrave celles du magasin

Le nombre deacuteleacutements affichables par une cellule dun GtkTreeView eacutetant varieacute il faut commencer par creacuteer unGtkCellRenderer qui peut ecirctre de diffeacuterents types

bull GtkCellRendererText pour afficher du texte

bull GtkCellRendererPixbuf pour les images

bull GtkCellRendererProgress permet dajouter une barre de progression

bull GtkCellRendererToggle affiche une case agrave cocher

Dans notre cas nous avons besoin que des deux premiers Voici le code pour la premiegravere colonne qui contiendralimage

mainc GtkCellRenderer p_renderer = NULL p_renderer = gtk_cell_renderer_pixbuf_new ()

Une fois la cellule creacuteeacutee il faut creacuteer la colonne agrave proprement parleacutee gracircce agrave la fonction

GtkTreeViewColumn gtk_tree_view_column_new_with_attributes (const gchar title GtkCellRenderer cell )

Apregraves le titre de la colonne et le GtkCellRenderer la fonction attend une chaicircne de caractegraveres qui diffegravere selonle type de GtkCellRenderer suivi du numeacutero de la colonne Comme il est possible de passer plusieurs couplesidentifiantnumeacutero de colonne nous terminons la liste par NULL

Et pour terminer on ajoute la colonne au GtkTextView

mainc gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

La deacutemarche est identique pour la seconde colonne

mainc p_renderer = gtk_cell_renderer_text_new () p_column = gtk_tree_view_column_new_with_attributes (NULL p_renderer text 1 NULL) gtk_tree_view_append_column (GTK_TREE_VIEW (p_tree_view) p_column)

Et comme nous navons pas besoin des en-tecirctes de colonnes nous les cachons

mainc gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (p_tree_view) FALSE)

Je suis passeacute rapidement sur cette partie car la documentation officielle nest pas tregravescomplegravete agrave ce sujet et le rocircle des fonctions nest pas tregraves claire

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 52 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVII-C-3 - Seacutelectionner un fichier

Nous arrivons agrave afficher le contenu dun dossier il nous reste plus quagrave reacuteagir agrave la seacutelection dune colonne Vouscommencez agrave ecirctre habitueacute il faut intercepter le signal row-activated du GtkTextView

mainc g_signal_connect (G_OBJECT (p_tree_view) row-activated G_CALLBACK (cb_select) NULL)

La fonction callback correspondante est diffeacuterente de ce quon a lhabitude de voir

void cb_select (GtkTreeView p_tree_view GtkTreePath arg1 GtkTreeViewColumn arg2 gpointer user_data)

Ces arguments vont nous permettrent de retrouver la cellule seacutelectionneacutee La meacutethode est comparable agrave celle quelon utilise pour les GtkTexView on commence par reacutecupeacuterer notre magasin sous forme de GtkTreeModel commenous pourrions le faire avec un GtkTextBuffer

GtkTreeModel p_tree_model = NULL

p_tree_model = gtk_tree_view_get_model (p_tree_view)

Ensuite agrave laide du GtkTreePath qui est une repreacutesentation du chemin pour acceacuteder agrave leacuteleacutement seacutelectionneacute nousreacutecupeacuterons un GtkTreeIter

GtkTreeIter iter gtk_tree_model_get_iter (p_tree_model ampiter arg1)

Et pour finir on reacutecupegravere le contenu de la seconde colonne gracircce au GtkTreeIter

gchar str = NULL gtk_tree_model_get (p_tree_model ampiter 1 ampstr -1)

Nous pourrions reacutecupeacuterer plusieurs colonnes en mecircme temps en ajoutant dautre couple numeacutero de colonnepointeursur un type de variable compatible avec ce que nous avons stockeacute dans le GtkListStore

Voilagrave cest la fin de la partie floue (je men excuse mais la documentation nest pas tregraves complegravete agrave se sujet il fautdonc faire des essais en tacirctonnant jusquagrave se que cela fonctionne sans forceacutement en connaicirctre les raisons ()

Maintenant que nous avons notre nom de fichier il faut retrouver son chemin complet et tester sil sagit dun dossierou non Ceci a deacutejagrave eacuteteacute vu lors de la creacuteation du GtkListStore

gchar file_name = NULL file_name = g_build_path (G_DIR_SEPARATOR_S docsdir_name str NULL) g_free (str) str = NULL if (g_file_test (file_name G_FILE_TEST_IS_DIR)) else

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 53 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Commenccedilons par le plus difficile dans le cas ougrave notre fichier est un dossier il suffit de remplacer le nom du dossieragrave afficher et de rafraicircchir le GtkListStore en faisant appel agrave la fonction dir_list

g_free (docsdir_name) docsdir_name = NULL docsdir_name = file_name dir_list ()

Difficile de faire plus simple Pour ouvrir un fichier il suffit de faire appel agrave la fonction open_file

open_file (file_name)

XVII-D - Code source

chapitre17zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 54 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XVIII - Notre signature

XVIII-A - Aperccedilu

Cliquez pour agrandir

XVIII-B - Boicircte A propos

Nous allons terminer cette initiation par un petit ajout qui va finir notre application une boicircte de dialogue A proposDepuis la version 26 de GTK+ il existe un widget qui va nous simplifier la vie GtkAboutDialog

Son utilisation est plutocirct simple il suffit de creacuteer le widget puis un certain nombre de fonctions permettent derenseigner les informations concernant le programme (auteur version licence) puis on affiche la boicircte de dialogue

void cb_about (GtkWidget p_widget gpointer user_data) GtkWidget p_about_dialog = NULL

p_about_dialog = gtk_about_dialog_new () gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (p_about_dialog) 10) gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (p_about_dialog) Editeur de texte) const gchar authors[2] = gege2061 NULL

gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (p_about_dialog) authors) gchar contents = NULL

if (g_file_get_contents (COPYING ampcontents NULL NULL)) gchar utf8 = NULL

utf8 = g_locale_to_utf8 (contents -1 NULL NULL NULL) g_free (contents) contents = NULL gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (p_about_dialog) utf8) g_free (utf8) utf8 = NULL gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (p_about_dialog) httpnicolasjdeveloppezcom) GdkPixbuf p_logo = NULL

p_logo = gdk_pixbuf_new_from_file (logopng NULL) gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (p_about_dialog) p_logo) gtk_dialog_run (GTK_DIALOG (p_about_dialog))

parametres inutilises (void)p_widget (void)user_data

Voilagrave rien de bien compliqueacute mais le reacutesultat obtenu est plutocirct sympathique

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 55 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

Bizarrement pour la fonction gtk_about_dialog_set_authors le tableau doit ecirctre deacuteclareacutecomme constant Un tableau non constant provoque une erreur de compilation

XVIII-C - Code source

chapitre18zip

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 56 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

XIX - Conclusion

XIX-A - Cest deacutejagrave fini

Eh oui cest la fin de ce tutoriel Mais si vous avez pris autant de plaisir que moi agrave lire et surtout commencer agrave maicirctriserla puissance de GTK+ alors ne vous inquieacutetez pas notre eacutediteur nen est qua la version 10 Les prochaines versionsne sont pas preacutevues pour la correction des bugs (enfin jespegravere) mais plutocirct ajouter de nouvelles fonctionnaliteacutes DVoici un aperccedilu des possibiliteacutes de GTK+ que je nai pas abordeacute ici mais qui pourront faire lobjet de tutoriels

bull La creacuteation dun eacutecran de deacutemarrage

bull Utilisation du widget GtkSourceView pour la coloration syntaxique

bull Le dragndrop

bull Une meilleure gestion des erreurs gracircce au GError

bull Et plein dautres choses que je ne connais pas encore

Je vous lai deacutejagrave dit mais je preacutefegravere le reacutepeacuteter la documentation de lAPI GTK+ est votre premiegravere sourcedinformation nheacutesitez pas agrave passer quelques minutes agrave chercher une fonction avant de recreacuteer la roue et surtoutfaites des essais cest comme cela que lon apprend (jai deacutecouvert eacutenormeacutement de fonctionnaliteacutes en eacutecrivant cetutoriel)

Si malgreacute cela vous avez des difficulteacutes lors de vos deacuteveloppements avec GTK+ les membres du forum C serontjen suis sucircr ravis de vous venir en aide )

XIX-B - Remerciements

Merci agrave loka fearyourself et agrave Miles pour leur relecture attentive de cet article

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements

GTK+ par lexemple par Nicolas Joseph (home) (Blog)

- 57 -Les sources preacutesenteacutes sur cette pages sont libres de droits et vous pouvez les utiliser agrave votre convenance Par contre la page de preacutesentation deces sources constitue une oeuvre intellectuelle proteacutegeacutee par les droits dauteurs Copyright copy 2006-2008 - Nicolas Joseph Aucune reproductionmecircme partielle ne peut ecirctre faite de ce site et de lensemble de son contenu textes documents images etc sans lautorisation expresse delauteur Sinon vous encourez selon la loi jusquagrave 3 ans de prison et jusquagrave 300 000 E de dommages et inteacuterecircts

httpnicolasjdeveloppezcomgtkcours

1 Widget est lacronyme de Windows Icons Dialog box Graphics Extensions Track ball plussouvent remplaceacute par WInDows gadGET2 Le C nest certes pas un langage fait preacutevu pour la POO mais en poussant agrave lextrecircme lanotion de type abstrait de donneacutee (TAD) GTK+ offre des possibiliteacutes proche de la POO3 ce que je vous conseille de faire pour voir le problegraveme noubliez pas de creacuteer une meacutethodecb_open sur le mecircme modegravele que cb_quit pour pouvoir compiler4 La glib contient de nombreuses fonctions fortes utiles il mest souvent arriveacute de coderune fonction qui eacutetait en fait preacutesente dans la glib nheacutesitez pas agrave perdre quelques minutes agravepasser sa documentation en revue pour eacuteviter une perte de temps5 Oui ccedila ressemble de loin aux iteacuterateurs du C pour ceux qui connaissent6 Il va falloir vous y faire agrave moins decirctre un surdoueacute il est impossible de connaicirctre lAPI parcoeur alors prenez le reacuteflexe davoir toujours la documentation agrave porteacutee de main7 Une boicircte de dialogue modale empecircche lutilisateur dinteragir avec sa fenecirctre parent8 Nous naurions pas eu ce problegraveme si nous commencions par creacuteer tous les widgets puis lesinteacutegrions agrave la fenecirctre Le problegraveme avec cette meacutethode cest que lon a besoin des variablesdeacutesignant les widgets jusquagrave la fin de la fonction ce qui nous empecirccherait de deacutecouper le codesous forme de blocs dans lesquels nous creacuteons chaque eacuteleacutement9 Ici fichier est agrave prendre au sens Unix du terme cest agrave dire que tout est fichier

  • Synopsis
  • Sommaire
  • I - Introduction
    • I-A - But de ce tutoriel
    • I-B - Connaissances requises
    • I-C - Quelques mots sur GTK+
      • I-C-1 - Historique
      • I-C-2 - Structure
      • I-C-3 - Pourquoi utiliser GTK+
        • I-D - Installation
          • I-D-1 - Windows
          • I-D-2 - Linux
            • I-E - La philosophie GTK+
            • I-F - Quelques notions de POO
            • I-G - Notre premier programme
            • I-H - Code source
              • II - Notre premiegravere fenecirctre
                • II-A - Aperccedilu
                • II-B - Creacuteation
                • II-C - Affichage
                • II-D - Destruction
                • II-E - Code source
                  • III - Fermer notre fenecirctre gracircce aux boutons
                    • III-A - Aperccedilu
                    • III-B - Les boutons poussoir
                    • III-C - Code source
                      • IV - Comment afficher plusieurs widgets
                        • IV-A - Aperccedilu
                        • IV-B - Le problegraveme
                        • IV-C - La solutions
                        • IV-D - Code source
                          • V - Afficher le contenue dun fichier
                            • V-A - Aperccedilu
                            • V-B - Saisir du texte
                            • V-C - Ouvrir un fichier
                            • V-D - La petite touche finale
                            • V-E - Code source
                              • VI - Choisir un fichier
                                • VI-A - Aperccedilu
                                • VI-B - Utilisation dun GtkFileChooserFile
                                • VI-C - Code source
                                  • VII - Interlude
                                    • VII-A - Code source
                                      • VIII - Sauvegarder les modification
                                        • VIII-A - Aperccedilu
                                        • VIII-B - Enregistrer
                                        • VIII-C - Enregistrer sous
                                        • VIII-D - Code source
                                          • IX - Creacuteer un nouveau document
                                            • IX-A - Aperccedilu
                                            • IX-B - Nouveau fichier
                                            • IX-C - Code source
                                              • X - Fermer
                                                • X-A - Aperccedilu
                                                • X-B - Fermer un fichier
                                                • X-C - Enregistrer avant de fermer
                                                • X-D - Code source
                                                  • XI - Les barres de deacutefilement
                                                    • XI-A - Aperccedilu
                                                    • XI-B - Ajouter des barres de deacutefilement
                                                    • XI-C - Code source
                                                      • XII - Les menus
                                                        • XII-A - Aperccedilu
                                                        • XII-B - Creacuteation du menu
                                                        • XII-C - Code source
                                                          • XIII - Les barres doutils
                                                            • XIII-A - Aperccedilu
                                                            • XIII-B - Creacuteation dune barre doutils
                                                            • XIII-C - Code source
                                                              • XIV - Les racourcis clavier
                                                                • XIV-A - Aperccedilu
                                                                • XIV-B - Mise en place des raccourcis clavier
                                                                • XIV-C - Code source
                                                                  • XV - Messages derreur
                                                                    • XV-A - Aperccedilu
                                                                    • XV-B - Ameacutelioration de nos fonctions daffichage derreur
                                                                    • XV-C - Code source
                                                                      • XVI - Ouvrir plusieurs fichiers en mecircme temps
                                                                        • XVI-A - Aperccedilu
                                                                        • XVI-B - Mise en place des onglets
                                                                        • XVI-C - Changement de page
                                                                        • XVI-D - Fermer un onglet
                                                                        • XVI-E - Fermer tous les onglets
                                                                        • XVI-F - Modifier le titre de la page
                                                                        • XVI-G - Code source
                                                                          • XVII - Afficher larborescence du disque
                                                                            • XVII-A - Aperccedilu
                                                                            • XVII-B - Preacuteparons le terrain
                                                                            • XVII-C - Creacuteation dun GtkTreeView
                                                                              • XVII-C-1 - Creacuteation du magasin
                                                                              • XVII-C-2 - Affichage de larborescence
                                                                              • XVII-C-3 - Seacutelectionner un fichier
                                                                                • XVII-D - Code source
                                                                                  • XVIII - Notre signature
                                                                                    • XVIII-A - Aperccedilu
                                                                                    • XVIII-B - Boicircte A propos
                                                                                    • XVIII-C - Code source
                                                                                      • XIX - Conclusion
                                                                                        • XIX-A - Cest deacutejagrave fini
                                                                                        • XIX-B - Remerciements