1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the documentation of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:FDL$
9 ** GNU Free Documentation License
10 ** Alternatively, this file may be used under the terms of the GNU Free
11 ** Documentation License version 1.3 as published by the Free Software
12 ** Foundation and appearing in the file included in the packaging of
16 ** Alternatively, this file may be used in accordance with the terms
17 ** and conditions contained in a signed written agreement between you
26 ****************************************************************************/
29 \page tutorials-addressbook-fr.html
31 \title Tutoriel "Carnet d'adresses"
32 \brief Une introduction à la programation d'interface graphique montrant comment construire une application simple avec Qt.
34 Ce tutoriel est une introduction à la programmation de GUI (interface utilisateur)
35 à l'aide des outils fournis par la plateforme multiplate-forme Qt.
37 \image addressbook-tutorial-screenshot.png
39 Ce tutoriel va nous amener à découvrir quelques technologies fondamentales fournies
43 \li Les Widgets et leur mise en page à l'aide des layouts
44 \li Les signaux et slots
45 \li Les structures de données de collections
46 \li Les entrées/sorties
49 Le code source du tutoriel est distribué avec Qt dans le dossier \c examples/tutorials/addressbook
51 Les chapitres du tutoriel:
54 \li \l{tutorials/addressbook-fr/part1}{Conception de l'interface utilisateur}
55 \li \l{tutorials/addressbook-fr/part2}{Ajouter des adresses}
56 \li \l{tutorials/addressbook-fr/part3}{Navigation entre les éléments}
57 \li \l{tutorials/addressbook-fr/part4}{éditer et supprimer des adresses}
58 \li \l{tutorials/addressbook-fr/part5}{Ajout d'une fonction de recherche}
59 \li \l{tutorials/addressbook-fr/part6}{Sauvegarde et chargement}
60 \li \l{tutorials/addressbook-fr/part7}{Fonctionnalités avancées}
63 La petite application que nous développerons ici ne possède pas tous les éléments
64 des interfaces dernier cri, elle va nous permettre d'utiliser les techniques de base
65 utilisées dans les applications plus complexes.
67 Lorsque vous aurez terminé ce tutoriel, nous vous recommandons de poursuivre avec l'exemple
68 "\l{mainwindows/application}{Application}", qui présente une interface simple utilisant
69 les menus et barres d'outils, la barre d'état, etc.
74 \page tutorials-addressbook-fr-part1.html
76 \example tutorials/addressbook-fr/part1
77 \title Carnet d'adresses 1 - Conception de l'interface utilisateur
79 La première partie de ce tutoriel traite de la conception d'une interface graphique
80 (GUI) basique, que l'on utilisera pour l'application Carnet d'adresses.
82 La première étape dans la création d'applications graphiques est la conception de
83 l'interface utilisateur. Dans ce chapitre, nous verrons comment créer les labels
84 et champs de saisie nécessaires à l'implementation d'un carnet d'adresses de base.
85 Le résultat attendu est illustré par la capture d'écran ci-dessous.
87 \image addressbook-tutorial-part1-screenshot.png
89 Nous allons avoir besoin de deux objets QLabel, \c nameLabel et \c addressLabel,
90 ainsi que deux champs de saisie: un objet QLineEdit, \c nameLine, et un objet
91 QTextEdit, \c addressText, afin de permettre à l'utilisateur d'entrer le nom d'un
92 contact et son adresse. Les widgets utilisés ainsi que leur placement sont visibles ci-dessous.
94 \image addressbook-tutorial-part1-labeled-screenshot.png
96 Trois fichiers sont nécessaires à l'implémentation de ce carnet d'adresses:
99 \li \c{addressbook.h} - le fichier de définition (header) pour la classe \c AddressBook,
100 \li \c{addressbook.cpp} - le fichier source, qui comprend l'implémentation de la classe
102 \li \c{main.cpp} - le fichier qui contient la méthode \c main() , et
103 une instance de la classe \c AddressBook.
106 \section1 Programmation en Qt - héritage
109 Lorsque l'on écrit des programmes avec Qt, on a généralement recours à
110 l'héritage depuis des objets Qt, afin d'y ajouter des fonctionnalités.
111 C'est l'un des concepts fondamentaux de la création de widgets personnalisés
112 ou de collections de widgets. Utiliser l'héritage afin de compléter
113 ou modifier le comportement d'un widget présente les avantages suivants:
116 \li La possibilité d'implémenter des méthodes virtuelles et des méthodes
117 virtuelles pures pour obtenir exactement ce que l'on souhaite, avec la possibilité
118 d'utiliser l'implémentation de la classe mère si besoin est.
119 \li Cela permet l'encapsulation partielle de l'interface utilisateur dans une classe,
120 afin que les autres parties de l'application n'aient pas à se soucier de chacun des
121 widgets qui forment l'interface utilisateur.
122 \li La classe fille peut être utilisée pour créer de nombreux widgets personnalisés
123 dans une même application ou bibliothèque, et le code de la classe fille peut être
124 réutilisé dans d'autres projets
127 Comme Qt ne fournit pas de widget standard pour un carnet d'adresses, nous
128 partirons d'une classe de widget Qt standard et y ajouterons des fonctionnalités.
129 La classe \c AddressBook crée dans ce tutoriel peut être réutilisée si on a besoin d'un
130 widget carnet d'adresses basique.
133 \section1 La classe AddressBook
135 Le fichier \l{tutorials/addressbook-fr/part1/addressbook.h}{\c addressbook.h} permet de
136 définir la classe \c AddressBook.
138 On commence par définir \c AddressBook comme une classe fille de QWidget et déclarer
139 un constructeur. On utilise également la macro Q_OBJECT pour indiquer que la classe
140 exploite les fonctionnalités de signaux et slots offertes par Qt ainsi que
141 l'internationalisation, bien que nous ne les utilisions pas à ce stade.
143 \snippet tutorials/addressbook-fr/part1/addressbook.h class definition
145 La classe contient les déclarations de \c nameLine et \c addressText,
146 les instances privées de QLineEdit et QTextEdit mentionnées précédemment.
147 Vous verrez, dans les chapitres à venir que les informations contenues
148 dans \c nameLine et \c addressText sont nécessaires à de nombreuses méthodes
149 du carnet d'adresses.
151 Il n'est pas nécessaire de déclarer les objets QLabel que nous allons utiliser
152 puisque nous n'aurons pas besoin d'y faire référence après leur création.
153 La façon dont Qt gère la parenté des objets est traitée dans la section suivante.
155 La macro Q_OBJECT implémente des fonctionnalités parmi les plus avancées de Qt.
156 Pour le moment, il est bon de voir la macro Q_OBJECT comme un raccourci nous
157 permettant d'utiliser les méthodes \l{QObject::}{tr()} et \l{QObject::}{connect()}.
159 Nous en avons maintenant terminé avec le fichier \c addressbook.h et allons
160 passer à l'implémentation du fichier \c addressbook.cpp.
162 \section1 Implémentation de la classe AddressBook
164 Le constructeur de la classe \c{AddressBook} prend en paramètre un QWidget, \e parent.
165 Par convention, on passe ce paramètre au constructeur de la classe mère.
166 Ce concept de parenté, où un parent peut avoir un ou plusieurs enfants, est utile
167 pour regrouper les Widgets avec Qt. Par exemple, si vous détruisez le parent,
168 tous ses enfants seront détruits égalament.
171 \snippet tutorials/addressbook/part1/addressbook.cpp constructor and input fields
173 à l'intérieur de ce constructeur, on déclare et instancie deux objets locaux
174 QLabel, \c nameLabel et \c addressLabel, de même on instancie \c nameLine et
175 \c addressText. La méthode \l{QObject::tr()}{tr()} renvoie une version traduite
176 de la chaîne de caractères, si elle existe; dans le cas contraire, elle renvoie
177 la chaîne elle même. On peut voir cette méthode comme un marqueur \tt{<insérer
178 la traduction ici>}, permettant de repérer les objets QString à considérer
179 pour traduire une application. Vous remarquerez, dans les chapitres à venir
180 comme dans les \l{Qt Examples}{exemples Qt}, qu'elle est utilisée chaque fois
181 que l'on utilise une chaîne susceptible d'être traduite.
183 Lorsque l'on programme avec Qt, il est utile de savoir comment fonctionnent les
184 agencements ou layouts. Qt fournit trois classes principales de layouts pour
185 contrôler le placement des widgets: QHBoxLayout, QVBoxLayout et QGridLayout.
187 \image addressbook-tutorial-part1-labeled-layout.png
189 On utilise un QGridLayout pour positionner nos labels et champs de saisie de manière
190 structurée. QGridLayout divise l'espace disponible en une grille, et place les
191 widgets dans les cellules que l'on spécifie par les numéros de ligne et de colonne.
192 Le diagramme ci-dessus présente les cellules et la position des widgets, et cette
193 organisation est obtenue à l'aide du code suivant:
195 \snippet tutorials/addressbook/part1/addressbook.cpp layout
197 On remarque que le label \c AddressLabel est positionné en utilisant Qt::AlignTop
198 comme argument optionnel. Ceci est destiné à assurer qu'il ne sera pas centré
199 verticalement dans la cellule (1,0). Pour un aperçu rapide des layouts de Qt,
200 consultez la section \l{Layout Management}.
202 Afin d'installer l'objet layout dans un widget, il faut appeler la méthode
203 \l{QWidget::setLayout()}{setLayout()} du widget en question:
205 \snippet tutorials/addressbook/part1/addressbook.cpp setting the layout
207 Enfin, on initialise le titre du widget à "Simple Address Book"
209 \section1 Exécution de l'application
211 Un fichier séparé, \c main.cpp, est utilisé pour la méthode \c main(). Dans cette
212 fonction, on crée une instance de QApplication, \c app. QApplication se charge de
213 des ressources communes à l'ensemble de l'application, tel que les polices de
214 caractères et le curseur par défaut, ainsi que de l'exécution de la boucle d'évènements.
215 De ce fait, il y a toujours un objet QApplication dans toute application graphique en Qt.
217 \snippet tutorials/addressbook/part1/main.cpp main function
219 On construit un nouveau widget \c AddressBook sur la pile et on invoque
220 sa méthode \l{QWidget::show()}{show()} pour l'afficher.
221 Cependant, le widget ne sera pas visible tant que la boucle d'évènements
222 n'aura pas été lancée. On démarre la boucle d'évènements en appelant la
223 méthode \l{QApplication::}{exec()} de l'application; le résultat renvoyé
224 par cette méthode est lui même utilisé comme valeur de retour pour la méthode
226 On comprend maintenant pourquoi \c AddressBook a été créé sur la pile: à la fin
227 du programme, l'objet sort du scope de la fonction \c main() et tous ses widgets enfants
228 sont supprimés, assurant ainsi qu'il n'y aura pas de fuites de mémoire.
232 \page tutorials-addressbook-fr-part2.html
234 \example tutorials/addressbook-fr/part2
235 \title Carnet d'adresses 2 - Ajouter des adresses
237 La prochaine étape pour créer notre carnet d'adresses est d'ajouter un soupçon
240 \image addressbook-tutorial-part2-add-contact.png
242 Nous allons fournir un bouton que l'utilisateur peut
243 cliquer pour ajouter un nouveau contact. Une structure de données est aussi
244 nécessaire afin de pouvoir stocker les contacts en mémoire.
246 \section1 Définition de la classe AddressBook
248 Maintenant que nous avons mis en place les labels et les champs de saisie,
249 nous ajoutons les boutons pour compléter le processus d'ajout d'un contact.
250 Cela veut dire que notre fichier \c addressbook.h a maintenant trois
251 objets QPushButton et trois slots publics correspondant.
253 \snippet tutorials/addressbook/part2/addressbook.h slots
255 Un slot est une méthode qui répond à un signal. Nous allons
256 voir ce concept en détail lorsque nous implémenterons la classe \c{AddressBook}.
257 Pour une explication détaillée du concept de signal et slot, vous pouvez
258 vous référer au document \l{Signals and Slots}.
260 Les trois objets QPushButton \c addButton, \c submitButton et \c cancelButton
261 sont maintenant inclus dans la déclaration des variables privées, avec
262 \c nameLine et \c addressText du chapitre précédent.
264 \snippet tutorials/addressbook/part2/addressbook.h pushbutton declaration
266 Nous avons besoin d'un conteneur pour stocker les contacts du carnet
267 d'adresses, de façon à pouvoir les énumérer et les afficher.
268 Un objet QMap, \c contacts, est utilisé pour ça, car il permet de stocker
269 des paires clé-valeur: le nom du contact est la \e{clé} et l'adresse du contact
272 \snippet tutorials/addressbook/part2/addressbook.h remaining private variables
274 Nous déclarons aussi deux objects QString privés: \c oldName et \c oldAddress.
275 Ces objets sont nécessaires pour conserver le nom et l'adresse du dernier contact
276 affiché avant que l'utilisateur ne clique sur le bouton "Add". Grâce à ces variables
277 si l'utilisateur clique sur "Cancel", il est possible de revenir
278 à l'affichage du dernier contact.
280 \section1 Implémentation de la classe AddressBook
282 Dans le constructeur de \c AddressBook, \c nameLine et
283 \c addressText sont mis en mode lecture seule, de façon à autoriser l'affichage
284 mais pas la modification du contact courant.
287 \snippet tutorials/addressbook/part2/addressbook.cpp setting readonly 1
289 \snippet tutorials/addressbook/part2/addressbook.cpp setting readonly 2
291 Ensuite, nous instancions les boutons \c addButton, \c submitButton, et
294 \snippet tutorials/addressbook/part2/addressbook.cpp pushbutton declaration
296 Le bouton \c addButton est affiché en invoquant la méthode \l{QPushButton::show()}
297 {show()}, tandis que \c submitButton et \c cancelButton sont cachés en invoquant
298 \l{QPushButton::hide()}{hide()}. Ces deux boutons ne seront affichés que lorsque
299 l'utilisateur cliquera sur "Add", et ceci est géré par la méthode \c addContact()
302 \snippet tutorials/addressbook/part2/addressbook.cpp connecting signals and slots
304 Nous connectons le signal \l{QPushButton::clicked()}{clicked()} de chaque bouton
305 au slot qui gèrera l'action.
306 L'image ci-dessous illustre ceci:
308 \image addressbook-tutorial-part2-signals-and-slots.png
310 Ensuite, nous arrangeons proprement les boutons sur la droite du widget
311 AddressBook, et nous utilisons un QVBoxLayout pour les aligner verticalement.
313 \snippet tutorials/addressbook/part2/addressbook.cpp vertical layout
315 La methode \l{QBoxLayout::addStretch()}{addStretch()} est utilisée pour
316 assurer que les boutons ne sont pas répartis uniformément, mais regroupés
317 dans la partie supperieure du widget. La figure ci-dessous montre la différence
318 si \l{QBoxLayout::addStretch()}{addStretch()} est utilisé ou pas.
320 \image addressbook-tutorial-part2-stretch-effects.png
322 Ensuite nous ajoutons \c buttonLayout1 à \c mainLayout, en utilisant
323 \l{QGridLayout::addLayout()}{addLayout()}. Ceci nous permet d'imbriquer les
324 mises en page puisque \c buttonLayout1 est maintenant un enfant de \c mainLayout.
326 \snippet tutorials/addressbook/part2/addressbook.cpp grid layout
328 Les coordonnées du layout global ressemblent maintenant à ça:
330 \image addressbook-tutorial-part2-labeled-layout.png
332 Dans la méthode \c addContact(), nous stockons les détails du dernier
333 contact affiché dans \c oldName et \c oldAddress. Ensuite, nous
334 vidons ces champs de saisie et nous désactivons le mode
335 lecture seule. Le focus est placé sur \c nameLine et on affiche
336 \c submitButton et \c cancelButton.
338 \snippet tutorials/addressbook/part2/addressbook.cpp addContact
340 La méthode \c submitContact() peut être divisée en trois parties:
343 \li Nous extrayons les détails du contact depuis \c nameLine et \c addressText
344 et les stockons dans des objets QString. Nous les validons pour s'assurer
345 que l'utilisateur n'a pas cliqué sur "Add" avec des champs de saisie
346 vides; sinon un message est affiché avec QMessageBox pour rappeller à
347 l'utilisateur que les deux champs doivent être complétés.
349 \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part1
351 \li Ensuite, nous vérifions si le contact existe déjà. Si aucun contacts
352 existant n'entre en conflit avec le nouveau, nous l'ajoutons à
353 \c contacts et nous affichons un QMessageBox pour informer l'utilisateur
354 que le contact a été ajouté.
356 \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part2
358 Si le contact existe déjà, nous affichons un QMessageBox pour informer
359 l'utilisateur du problème.
360 Notre objet \c contacts est basé sur des paires clé-valeur formés par
361 le nom et l'adresse, nous voulons nous assurer que la \e clé est unique.
363 \li Une fois que les deux vérifications précédentes ont été traitées,
364 nous restaurons les boutons à leur état normal à l'aide du code
367 \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part3
371 La capture d'écran ci-dessous montre l'affichage fournit par un objet
372 QMessageBox, utilisé ici pour afficher un message d'information
375 \image addressbook-tutorial-part2-add-successful.png
377 La méthode \c cancel() restaure les détails du dernier contact, active
378 \c addButton, et cache \c submitButton et \c cancelButton.
380 \snippet tutorials/addressbook/part2/addressbook.cpp cancel
382 L'idée générale pour augmenter la flexibilité lors de l'ajout d'un
383 contact est de donner la possiblité de cliquer sur "Add"
384 ou "Cancel" à n'importe quel moment.
385 L'organigramme ci-dessous reprend l'ensemble des interactions dévelopées
388 \image addressbook-tutorial-part2-add-flowchart.png
392 \page tutorials-addressbook-fr-part3.html
394 \example tutorials/addressbook-fr/part3
395 \title Carnet d'adresses 3 - Navigation entre les éléments
397 L'application "Carnet d'adresses" est maintenant à moitié terminée. Il
398 nous faut maintenant ajouter quelques fonctions pour naviguer entre
399 les contacts. Avant de commencer, il faut se décider sur le type de structure de
400 données le plus approprié pour stocker les contacts.
402 Dans le chapitre 2, nous avons utilisé un QMap utilisant des paires clé-valeur,
403 avec le nom du contact comme \e clé, et l'adresse du contact comme \e valeur.
404 Cela fonctionnait bien jusqu'ici, mais pour ajouter la navigation entre les
405 entrées, quelques améliorations sont nécessaires.
407 Nous améliorerons le QMap en le faisant ressembler à une structure de données
408 similaire à une liste liée, où tous les éléments sont connectés, y compris
409 le premier et le dernier élément. La figure ci-dessous illustre cette structure
412 \image addressbook-tutorial-part3-linkedlist.png
414 \section1 Définition de la classe AddressBook
416 Pour ajouter les fonctions de navigation au carnet d'adresses, nous avons
417 besoin de deux slots supplémentaires dans notre classe \c AddressBook:
418 \c next() et \c previous(). Ceux-ci sont ajoutés au fichier addressbook.h:
420 \snippet tutorials/addressbook/part3/addressbook.h navigation functions
422 Nous avons aussi besoin de deux nouveaux objets QPushButton, nous ajoutons
423 donc les variables privées \c nextButton et \c previousButton.
425 \snippet tutorials/addressbook/part3/addressbook.h navigation pushbuttons
427 \section1 Implémentation de la classe AddressBook
429 A l'intérieur du constructeur de \c AddressBook, dans \c addressbook.cpp, nous
430 instancions \c nextButton et \c previousButton et nous les désactivons
431 par défaut. Nous faisons ceci car la navigation ne doit être activée
432 que lorsqu'il y a plus d'un contact dans le carnet d'adresses.
434 \snippet tutorials/addressbook/part3/addressbook.cpp navigation pushbuttons
436 Nous connectons alors ces boutons à leur slots respectifs:
438 \snippet tutorials/addressbook/part3/addressbook.cpp connecting navigation signals
440 L'image ci-dessous montre l'interface utilisateur que nous allons créer.
441 Remarquez que cela ressemble de plus en plus à l'interface du programme
444 \image addressbook-tutorial-part3-screenshot.png
446 Nous suivons les conventions pour les fonctions \c next() et \c previous()
447 en plaçant \c nextButton à droite et \c previousButton à gauche. Pour
448 faire cette mise en page intuitive, nous utilisons un QHBoxLayout pour
449 placer les widgets côte à côte:
451 \snippet tutorials/addressbook/part3/addressbook.cpp navigation layout
453 L'objet QHBoxLayout, \c buttonLayout2, est ensuite ajouté à \c mainLayout.
455 \snippet tutorials/addressbook/part3/addressbook.cpp adding navigation layout
457 La figure ci-dessous montre les systèmes de coordonnées pour les widgets du
459 \image addressbook-tutorial-part3-labeled-layout.png
461 Dans notre méthode \c addContact(), nous avons desactivé ces boutons
462 pour être sûr que l'utilisateur n'utilise pas la navigation lors de
463 l'ajout d'un contact.
465 \snippet tutorials/addressbook/part3/addressbook.cpp disabling navigation
467 Dans notre méthode \c submitContact(), nous activons les boutons de
468 navigation, \c nextButton et \c previousButton, en fonction de la
469 taille de \c contacts. Commen mentionné plus tôt, la navigation n'est
470 activée que si il y a plus d'un contact dans le carnet d'adresses.
471 Les lignes suivantes montrent comment faire cela:
473 \snippet tutorials/addressbook/part3/addressbook.cpp enabling navigation
475 Nous incluons aussi ces lignes de code dans le bouton \c cancel().
477 Souvenez vous que nous voulons émuler une liste-liée ciruculaire à
478 l'aide de l'objet QMap, \c contacts. Pour faire cela, nous obtenons un itérateur
479 sur \c contact dans la méthode \c next(), et ensuite:
482 \li Si l'itérateur n'est pas à la fin de \c contacts, nous l'incrémentons
483 \li Si l'itérateur est à la fin de \c contacts, nous changeons sa position
484 jusqu'au début de \c contacts. Cela donne l'illusion que notre QMap
485 fonctionne comme une liste circulaire.
488 \snippet tutorials/addressbook/part3/addressbook.cpp next() function
490 Une fois que nous avons itéré jusqu'à l'objet recherché dans \c contacts,
491 nous affichons son contenu sur \c nameLine et \c addressText.
493 De la même façon, pour la méthode \c previous(), nous obtenons un
494 itérateur sur \c contacts et ensuite:
497 \li Si l'itérateur est à la fin de \c contacts, on réinitialise
498 l'affichage et on retourne.
499 \li Si l'itérateur est au début de \c contacts, on change sa
500 position jusqu'à la fin
501 \li Ensuite, on décrémente l'itérateur
504 \snippet tutorials/addressbook/part3/addressbook.cpp previous() function
506 à nouveau, nous affichons le contenu de l'objet courant dans \c contacts.
512 \page tutorials-addressbook-fr-part4.html
514 \example tutorials/addressbook-fr/part4
515 \title Carnet d'Adresses 4 - éditer et supprimer des adresses
518 Dans ce chapitre, nous verrons comment modifier les données des contacts
519 contenus dans l'application carnet d'adresses.
522 \image addressbook-tutorial-screenshot.png
524 Nous avons maintenant un carnet d'adresses qui ne se contente pas de
525 lister des contacts de façon ordonnée, mais permet également la
526 navigation. Il serait pratique d'inclure des fonctions telles qu'éditer et
527 supprimer, afin que les détails associés à un contact puissent être
528 modifiés lorsque c'est nécessaire. Cependant, cela requiert une légère
529 modification, sous la forme d'énumérations. Au chapitre précédent, nous avions deux
530 modes: \c {AddingMode} et \c {NavigationMode}, mais ils n'étaient pas
531 définis en tant qu'énumérations. Au lieu de ça, on activait et désactivait les
532 boutons correspondants manuellement, au prix de multiples redondances dans
535 Dans ce chapitre, on définit l'énumération \c Mode avec trois valeurs possibles.
538 \li \c{NavigationMode},
539 \li \c{AddingMode}, et
543 \section1 Définition de la classe AddressBook
545 Le fichier \c addressbook.h est mis a jour pour contenir l'énumération \c Mode :
547 \snippet tutorials/addressbook/part4/addressbook.h Mode enum
549 On ajoute également deux nouveaux slots, \c editContact() et
550 \c removeContact(), à notre liste de slots publics.
552 \snippet tutorials/addressbook/part4/addressbook.h edit and remove slots
554 Afin de basculer d'un mode à l'autre, on introduit la méthode
555 \c updateInterface() pour contrôller l'activation et la désactivation de
556 tous les objets QPushButton. On ajoute également deux nouveaux boutons,
557 \c editButton et \c removeButton, pour les fonctions d'édition
558 et de suppression mentionnées plus haut.
560 \snippet tutorials/addressbook/part4/addressbook.h updateInterface() declaration
562 \snippet tutorials/addressbook/part4/addressbook.h buttons declaration
564 \snippet tutorials/addressbook/part4/addressbook.h mode declaration
566 Enfin, on déclare \c currentMode pour garder une trace du mode
567 actuellement utilisé.
569 \section1 Implémentation de la classe AddressBook
571 Il nous faut maintenant implémenter les fonctionnalités de changement de
572 mode de l'application carnet d'adresses. Les boutons \c editButton et
573 \c removeButton sont instanciés et désactivés par défaut, puisque le
574 carnet d'adresses démarre sans aucun contact en mémoire.
576 \snippet tutorials/addressbook/part4/addressbook.cpp edit and remove buttons
578 Ces boutons sont ensuite connectés à leurs slots respectifs,
579 \c editContact() et \c removeContact(), avant d'être ajoutés à
582 \snippet tutorials/addressbook/part4/addressbook.cpp connecting edit and remove
584 \snippet tutorials/addressbook/part4/addressbook.cpp adding edit and remove to the layout
586 La methode \c editContact() place les anciens détails du contact dans
587 \c oldName et \c oldAddress, avant de basculer vers le mode
588 \c EditingMode. Dans ce mode, les boutons \c submitButton et
589 \c cancelButton sont tous deux activés, l'utilisateur peut par conséquent
590 modifier les détails du contact et cliquer sur l'un de ces deux boutons
593 \snippet tutorials/addressbook/part4/addressbook.cpp editContact() function
595 La méthode \c submitContact() a été divisée en deux avec un bloc
596 \c{if-else}. On teste \c currentMode pour voir si le mode courant est
597 \c AddingMode. Si c'est le cas, on procède à l'ajout.
599 \snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function beginning
601 \snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function part1
603 Sinon, on s'assure que \c currentMode est en \c EditingMode. Si c'est le
604 cas, on compare \c oldName et \c name. Si le nom a changé, on supprime
605 l'ancien contact de \c contacts et on insère le contact mis a jour.
607 \snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function part2
609 Si seule l'adresse a changé (i.e. \c oldAddress n'est pas identique à
610 \c address), on met à jour l'adresse du contact. Enfin on règle
611 \c currentMode à \c NavigationMode. C'est une étape importante puisque
612 c'est cela qui réactive tous les boutons désactivés.
614 Afin de retirer un contact du carnet d'adresses, on implémente la méthode
615 \c removeContact(). Cette méthode vérifie que le contact est présent dans
618 \snippet tutorials/addressbook/part4/addressbook.cpp removeContact() function
620 Si c'est le cas, on affiche une boîte de dialogue QMessageBox, demandant
621 confirmation de la suppression à l'utilisateur. Une fois la confirmation
622 effectuée, on appelle \c previous(), afin de s'assurer que l'interface
623 utilisateur affiche une autre entrée, et on supprime le contact en
624 utilisant le méthode \l{QMap::remove()}{remove()} de \l{QMap}. Dans un
625 souci pratique, on informe l'utilisateur de la suppression par le biais
626 d'une autre QMessageBox. Les deux boîtes de dialogue utilisées dans cette
627 méthode sont représentées ci-dessous.
629 \image addressbook-tutorial-part4-remove.png
631 \section2 Mise à jour de l'Interface utilisateur
633 On a évoqué plus haut la méthode \c updateInterface() comme moyen
634 d'activer et de désactiver les différents boutons de l'interface en
635 fonction du mode. Cette méthode met à jour le mode courant selon
636 l'argument \c mode qui lui est passé, en l'assignant à \c currentMode,
637 avant de tester sa valeur.
639 Chacun des boutons est ensuite activé ou désactivé, en fonction du mode.
640 Le code source pour les cas \c AddingMode et \c EditingMode est visible
643 \snippet tutorials/addressbook/part4/addressbook.cpp update interface() part 1
645 Dans le cas de \c NavigationMode, en revanche, des tests conditionnels
646 sont passés en paramètre de QPushButton::setEnabled(). Ceci permet de
647 s'assurer que les boutons \c editButton et \c removeButton ne sont activés
648 que s'il existe au moins un contact dans le carnet d'adresses;
649 \c nextButton et \c previousButton ne sont activés que lorsqu'il existe
650 plus d'un contact dans le carnet d'adresses.
652 \snippet tutorials/addressbook/part4/addressbook.cpp update interface() part 2
654 En effectuant les opérations de réglage du mode et de mise à jour de
655 l'interface utilisateur au sein de la même méthode, on est à l'abri de
656 l'éventualité où l'interface utilisateur se "désynchronise" de l'état
657 interne de l'application.
662 \page tutorials-addressbook-fr-part5.html
664 \example tutorials/addressbook-fr/part5
665 \title Carnet d'adresse 5 - Ajout d'une fonction de recherche
667 Dans ce chapitre, nous allons voir les possibilités pour rechercher
668 des contacts dans le carnet d'adresse.
670 \image addressbook-tutorial-part5-screenshot.png
672 Plus nous ajoutons des contacts dans l'application, plus
673 il devient difficile de naviguer avec les boutons \e Next et \e Previous.
674 Dans ce cas, une fonction de recherche serait plus efficace pour rechercher
676 La capture d'écran ci-dessus montre le bouton de recherche \e Find et sa position
677 dans le paneau de bouton.
679 Lorsque l'utilisateur clique sur le bouton \e Find, il est courant d'afficher
680 une boîte de dialogue qui demande à l'utilisateur d'entrer un nom de contact.
681 Qt fournit la classe QDialog, que nous sous-classons dans ce chapitre pour
682 implémenter la class \c FindDialog.
684 \section1 Définition de la classe FindDialog
686 \image addressbook-tutorial-part5-finddialog.png
688 Pour sous-classer QDialog, nous commençons par inclure le header de
689 QDialog dans le fichier \c finddialog.h. De plus, nous déclarons les
690 classes QLineEdit et QPushButton car nous utilisons ces widgets dans
691 notre classe dialogue.
693 Tout comme dans la classe \c AddressBook, la classe \c FindDialog utilise
694 la macro Q_OBJECT et son constructeur est défini de façon à accepter
695 un QWidget parent, même si cette boîte de dialogue sera affichée dans une
698 \snippet tutorials/addressbook/part5/finddialog.h FindDialog header
700 Nous définissons la méthode publique \c getFindText() pour être utilisée
701 par les classes qui instancient \c FindDialog, ce qui leur permet d'obtenir
702 le texte entré par l'utilisateur. Un slot public, \c findClicked(), est
703 défini pour prendre en charge le texte lorsque l'utilisateur clique sur
704 le bouton \uicontrol Find.
706 Finalement, nous définissons les variables privées \c findButton,
707 \c lineEdit et \c findText, qui correspondent respectivement au bouton
708 \uicontrol Find, au champ de texte dans lequel l'utilisateur tape le texte
709 à rechercher, et à une variable interne stockant le texte pour une
710 utilisation ultérieure.
712 \section1 Implémentation de la classe FindDialog
714 Dans le constructeur de \c FindDialog, nous instancions les objets des
715 variables privées \c lineEdit, \c findButton et \c findText. Nous utilisons ensuite
716 un QHBoxLayout pour positionner les widgets.
718 \snippet tutorials/addressbook/part5/finddialog.cpp constructor
720 Nous mettons en place la mise en page et le titre de la fenêtre, et
721 nous connectons les signaux aux slots. Remarquez que le signal
722 \l{QPushButton::clicked()}{clicked()} de \c{findButton} est connecté
723 à \c findClicked() et \l{QDialog::accept()}{accept()}. Le slot
724 \l{QDialog::accept()}{accept()} fourni par le QDialog ferme
725 la boîte de dialogue et lui donne le code de retour \l{QDialog::}{Accepted}.
726 Nous utilisons cette fonction pour aider la méthode \c findContact() de la classe
727 \c{AddressBook} à savoir si l'objet \c FindDialog a été fermé. Ceci sera
728 expliqué plus loin lorsque nous verrons la méthode \c findContact().
730 \image addressbook-tutorial-part5-signals-and-slots.png
732 Dans \c findClicked(), nous validons le champ de texte pour nous
733 assurer que l'utilisateur n'a pas cliqué sur le bouton \uicontrol Find sans
734 avoir entré un nom de contact. Ensuite, nous stockons le texte du champ
735 d'entrée \c lineEdit dans \c findText. Et finalement nous vidons le
736 contenu de \c lineEdit et cachons la boîte de dialogue.
738 \snippet tutorials/addressbook/part5/finddialog.cpp findClicked() function
740 La variable \c findText a un accesseur publique associé: \c getFindText().
741 Étant donné que nous ne modifions \c findText directement que dans le
742 constructeur et la méthode \c findClicked(), nous ne créons pas
743 de manipulateurs associé à \c getFindText().
744 Puisque \c getFindText() est publique, les classes instanciant et
745 utilisant \c FindDialog peuvent toujours accéder à la chaîne de
746 caractères que l'utilisateur a entré et accepté.
748 \snippet tutorials/addressbook/part5/finddialog.cpp getFindText() function
750 \section1 Définition de la classe AddressBook
752 Pour utiliser \c FindDialog depuis la classe \c AddressBook, nous
753 incluons \c finddialog.h dans le fichier \c addressbook.h.
755 \snippet tutorials/addressbook/part5/addressbook.h include finddialog's header
757 Jusqu'ici, toutes les fonctionnalités du carnet d'adresses ont un
758 QPushButton et un slot correspondant. De la même façon, pour la
759 fonctionnalité \uicontrol Find, nous avons \c findButton et \c findContact().
761 Le \c findButton est déclaré comme une variable privée et la
762 méthode \c findContact() est déclarée comme un slot public.
764 \snippet tutorials/addressbook/part5/addressbook.h findContact() declaration
766 \snippet tutorials/addressbook/part5/addressbook.h findButton declaration
768 Finalement, nous déclarons la variable privée \c dialog que nous allons
769 utiliser pour accéder à une instance de \c FindDialog.
771 \snippet tutorials/addressbook/part5/addressbook.h FindDialog declaration
773 Une fois que nous avons instancié la boîte de dialogue, nous voulons l'utiliser
774 plus qu'une fois. Utiliser une variable privée nous permet d'y référer
775 à plus d'un endroit dans la classe.
777 \section1 Implémentation de la classe AddressBook
779 Dans le constructeur de \c AddressBook, nous instancions nos objets privés,
780 \c findbutton et \c findDialog:
782 \snippet tutorials/addressbook/part5/addressbook.cpp instantiating findButton
784 \snippet tutorials/addressbook/part5/addressbook.cpp instantiating FindDialog
786 Ensuite, nous connectons le signal \l{QPushButton::clicked()}{clicked()} de
787 \c{findButton} à \c findContact().
789 \snippet tutorials/addressbook/part5/addressbook.cpp signals and slots for find
791 Maintenant, tout ce qui manque est le code de notre méthode \c findContact():
793 \snippet tutorials/addressbook/part5/addressbook.cpp findContact() function
795 Nous commençons par afficher l'instance de \c FindDialog, \c dialog.
796 L'utilisateur peut alors entrer le nom du contact à rechercher. Lorsque
797 l'utilisateur clique sur le bouton \c findButton, la boîte de dialogue est
798 masquée et le code de retour devient QDialog::Accepted. Ce code de retour
799 vient remplir la condition du premier if.
801 Ensuite, nous extrayons le texte que nous utiliserons pour la recherche,
802 il s'agit ici de \c contactName obtenu à l'aide de la méthode \c getFindText()
803 de \c FindDialog. Si le contact existe dans le carnet d'adresse, nous
804 l'affichons directement. Sinon, nous affichons le QMessageBox suivant pour
805 indiquer que la recherche à échouée.
807 \image addressbook-tutorial-part5-notfound.png
811 \page tutorials-addressbook-part6.html
813 \example tutorials/addressbook-fr/part6
814 \title Carnet d'Adresses 6 - Sauvegarde et chargement
816 Ce chapitre couvre les fonctionnalités de gestion des fichiers de Qt que
817 l'on utilise pour écrire les procédures de sauvegarde et chargement pour
818 l'application carnet d'adresses.
820 \image addressbook-tutorial-part6-screenshot.png
822 Bien que la navigation et la recherche de contacts soient des
823 fonctionnalités importantes, notre carnet d'adresses ne sera pleinement
824 utilisable qu'une fois que l'on pourra sauvegarder les contacts existants
825 et les charger à nouveau par la suite.
826 Qt fournit de nombreuses classes pour gérer les \l{Input/Output and
827 Networking}{entrées et sorties}, mais nous avons choisi de nous contenter d'une
828 combinaison de deux classes simples à utiliser ensemble: QFile et QDataStream.
830 Un objet QFile représente un fichier sur le disque qui peut être lu, et
831 dans lequel on peut écrire. QFile est une classe fille de la classe plus
832 générique QIODevice, qui peut représenter différents types de
835 Un objet QDataStream est utilisé pour sérialiser des données binaires
836 dans le but de les passer à un QIODevice pour les récupérer dans le
837 futur. Pour lire ou écrire dans un QIODevice, il suffit d'ouvrir le
838 flux, avec le périphérique approprié en paramètre, et d'y lire ou
841 \section1 Définition de la classe AddressBook
843 On déclare deux slots publics, \c saveToFile() et \c loadFromFile(),
844 ainsi que deux objets QPushButton, \c loadButton et \c saveButton.
846 \snippet tutorials/addressbook/part6/addressbook.h save and load functions declaration
848 \snippet tutorials/addressbook/part6/addressbook.h save and load buttons declaration
850 \section1 Implémentation de la classe AddressBook
852 Dans notre constructeur, on instancie \c loadButton et \c saveButton.
853 Idéalement, l'interface serait plus conviviale avec des boutons
854 affichant "Load contacts from a file" et "Save contacts to a file". Mais
855 compte tenu de la dimension des autres boutons, on initialise les labels
856 des boutons à \uicontrol{Load...} et \uicontrol{Save...}. Heureusement, Qt offre une
857 façon simple d'ajouter des info-bulles avec
858 \l{QWidget::setToolTip()}{setToolTip()}, et nous l'exploitons de la façon
859 suivante pour nos boutons:
861 \snippet tutorials/addressbook/part6/addressbook.cpp tooltip 1
863 \snippet tutorials/addressbook/part6/addressbook.cpp tooltip 2
865 Bien qu'on ne cite pas le code correspondant ici, nous ajoutons ces deux boutons au
866 layout de droite, \c button1Layout, comme pour les fonctionnalités précédentes, et
867 nous connectons leurs signaux
868 \l{QPushButton::clicked()}{clicked()} à leurs slots respectifs.
870 Pour la sauvegarde, on commence par récupérer le nom de fichier
871 \c fileName, en utilisant QFileDialog::getSaveFileName(). C'est une
872 méthode pratique fournie par QFileDialog, qui ouvre une boîte de
873 dialogue modale et permet à l'utilisateur d'entrer un nom de fichier ou
874 de choisir un fichier \c{.abk} existant. Les fichiers \c{.abk}
875 correspondent à l'extension choisie pour la sauvegarde des contacts de
876 notre carnet d'adresses.
878 \snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part1
880 La boîte de dialogue affichée est visible sur la capture d'écran ci-
883 \image addressbook-tutorial-part6-save.png
885 Si \c fileName n'est pas vide, on crée un objet QFile, \c file, à partir
886 de \c fileName. QFile fonctionne avec QDataStream puisqu'il dérive de
889 Ensuite, on essaie d'ouvrir le fichier en écriture, ce qui correspond au
890 mode \l{QIODevice::}{WriteOnly}. Si cela échoue, on en informe
891 l'utilisateur avec une QMessageBox.
893 \snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part2
895 Dans le cas contraire, on instancie un objet QDataStream, \c out, afin
896 d'écrire dans le fichier ouvert. QDataStream nécessite que la même
897 version de flux soit utilisée pour la lecture et l'écriture. On s'assure
898 que c'est le cas en spécifiant explicitement d'utiliser la
899 \l{QDataStream::Qt_4_5}{version introduite avec Qt 4.5} avant de
900 sérialiser les données vers le fichier \c file.
902 \snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part3
904 Pour le chargement, on récupère également \c fileName en utilisant
905 QFileDialog::getOpenFileName(). Cette méthode est l'homologue de
906 QFileDialog::getSaveFileName() et affiche également une boîte de
907 dialogue modale permettant à l'utilisateur d'entrer un nom de fichier ou
908 de selectionner un fichier \c{.abk} existant, afin de le charger dans le
911 \snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part1
913 Sous Windows, par exemple, cette méthode affiche une boîte de dialogue
914 native pour la sélection de fichier, comme illustré sur la capture
917 \image addressbook-tutorial-part6-load.png
919 Si \c fileName n'est pas vide, on utilise une fois de plus un objet
920 QFile, \c file, et on tente de l'ouvrir en lecture, avec le mode
921 \l{QIODevice::}{ReadOnly}. De même que précédemment dans notre
922 implémentation de \c saveToFile(), si cette tentative s'avère
923 infructueuse, on en informe l'utilisateur par le biais d'une
926 \snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part2
928 Dans le cas contraire, on instancie un objet QDataStream, \c in, en
929 spécifiant la version à utiliser comme précédemment, et on lit les
930 informations sérialisées vers la structure de données \c contacts. Notez
931 qu'on purge \c contacts avant d'y mettre les informations lues afin de
932 simplifier le processus de lecture de fichier. Une façon plus avancée de
933 procéder serait de lire les contacts dans un objet QMap temporaire, et
934 de copier uniquement les contacts n'existant pas encore dans
937 \snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part3
939 Pour afficher les contacts lus depuis le fichier, on doit d'abord
940 valider les données obtenues afin de s'assurer que le fichier lu
941 contient effectivement des entrées de carnet d'adresses. Si c'est le
942 cas, on affiche le premier contact; sinon on informe l'utilisateur du
943 problème par une QMessageBox. Enfin, on met à jour l'interface afin
944 d'activer et de désactiver les boutons de façon appropriée.
948 \page tutorials-addressbook-fr-part7.html
950 \example tutorials/addressbook-fr/part7
951 \title Carnet d'adresse 7 - Fonctionnalités avancées
953 Ce chapitre couvre quelques fonctionnalités additionnelles qui
954 feront de notre carnet d'adresses une application plus pratique
955 pour une utilisation quotidienne.
957 \image addressbook-tutorial-part7-screenshot.png
959 Bien que notre application carnet d'adresses soit utile en tant que telle,
960 il serait pratique de pouvoir échanger les contacts avec d'autres applications.
961 Le format vCard est un un format de fichier populaire pour échanger
963 Dans ce chapitre, nous étendrons notre carnet d'adresses pour permettre
964 d'exporter des contacts dans des fichiers vCard \c{.vcf}.
966 \section1 Définition de la classe AddressBook
968 Nous ajoutons un objet QPushButton, \c exportButton, et un slot
969 public correspondant, \c exportAsVCard(), à notre classe \c AddressBook
970 dans le fichier \c addressbook.h.
972 \snippet tutorials/addressbook/part7/addressbook.h exportAsVCard() declaration
974 \snippet tutorials/addressbook/part7/addressbook.h exportButton declaration
976 \section1 Implémentation de la classe AddressBook
978 Dans le constructeur de \c AddressBook, nous connectons le signal
979 \l{QPushButton::clicked()}{clicked()} de \c{exportButton} au slot
981 Nous ajoutons aussi ce bouton à \c buttonLayout1, le layout responsable
982 du groupe de boutons sur la droite.
984 Dans la méthode \c exportAsVCard(), nous commençons par extraire le
985 nom du contact dans \c name. Nous déclarons \c firstname, \c lastName et
987 Ensuite, nous cherchons la position du premier espace blanc de \c name.
988 Si il y a un espace, nous séparons le nom du contact en \c firstName et
989 \c lastName. Finalement, nous remplaçons l'espace par un underscore ("_").
990 Si il n'y a pas d'espace, nous supposons que le contact ne comprend que
993 \snippet tutorials/addressbook/part7/addressbook.cpp export function part1
995 Comme pour la méthode \c saveToFile(), nous ouvrons une boîte de dialogue
996 pour donner la possibilité à l'utilisateur de choisir un emplacement pour
997 le fichier. Avec le nom de fichier choisi, nous créons une instance de QFile
1000 Nous essayons d'ouvrir le fichier en mode \l{QIODevice::}{WriteOnly}. Si
1001 cela échoue, nous affichons un QMessageBox pour informer l'utilisateur
1002 à propos de l'origine du problème et nous quittons la méthode. Sinon, nous passons le
1003 fichier comme paramètre pour créer un objet QTextStream, \c out. De la même façon que
1004 QDataStream, la classe QTextStream fournit les fonctionnalités pour
1005 lire et écrire des fichiers de texte. Grâce à celà, le fichier \c{.vcf}
1006 généré pourra être ouvert et édité à l'aide d'un simple éditeur de texte.
1008 \snippet tutorials/addressbook/part7/addressbook.cpp export function part2
1010 Nous écrivons ensuite un fichier vCard avec la balise \c{BEGIN:VCARD},
1011 suivit par \c{VERSION:2.1}.
1012 Le nom d'un contact est écrit à l'aide de la balise \c{N:}. Pour la balise
1013 \c{FN:}, qui remplit le titre du contact, nous devons vérifier si le contact
1014 à un nom de famille défini ou non. Si oui, nous utilions les détails de
1015 \c nameList pour remplir le champ, dans le cas contraire on écrit uniquement le contenu
1018 \snippet tutorials/addressbook/part7/addressbook.cpp export function part3
1020 Nous continuons en écrivant l'adresse du contact. Les points-virgules
1021 dans l'adresse sont échappés à l'aide de "\\", les retours de ligne sont
1022 remplacés par des points-virgules, et les vigules sont remplacées par des espaces.
1023 Finalement nous écrivons les balises \c{ADR;HOME:;} suivies par l'adresse
1024 et la balise \c{END:VCARD}.
1026 \snippet tutorials/addressbook/part7/addressbook.cpp export function part4
1028 À la fin de la méthode, un QMessageBox est affiché pour informer l'utilisateur
1029 que la vCard a été exportée avec succès.
1031 \e{vCard est une marque déposée de \l{http://www.imc.org}
1032 {Internet Mail Consortium}}.