|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the documentation of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 /*! |
|
43 \page tutorials-addressbook-fr.html |
|
44 |
|
45 \startpage {index.html}{Qt Reference Documentation} |
|
46 \contentspage Tutorials |
|
47 \nextpage {tutorials/addressbook-fr/part1}{Chapitre 1} |
|
48 |
|
49 \title Tutoriel "Carnet d'adresses" |
|
50 \brief Une introduction à la programation d'interface graphique montrant comment construire une application simple avec Qt. |
|
51 |
|
52 Ce tutoriel est une introduction à la programmation de GUI (interface utilisateur) |
|
53 à l'aide des outils fournis par la plateforme multiplate-forme Qt. |
|
54 |
|
55 \image addressbook-tutorial-screenshot.png |
|
56 |
|
57 Ce tutoriel va nous amener à découvrir quelques technologies fondamentales fournies |
|
58 par Qt, tel que: |
|
59 |
|
60 \list |
|
61 \o Les Widgets et leur mise en page à l'aide des layouts |
|
62 \o Les signaux et slots |
|
63 \o Les structures de données de collections |
|
64 \o Les entrées/sorties |
|
65 \endlist |
|
66 |
|
67 Si c'est votre premier contact avec Qt, lisez \l{How to Learn Qt}{Comment apprendre Qt} |
|
68 si ce n'est déjà fait. |
|
69 |
|
70 Le code source du tutoriel est distribué avec Qt dans le dossier \c examples/tutorials/addressbook |
|
71 |
|
72 Les chapitres du tutoriel: |
|
73 |
|
74 \list 1 |
|
75 \o \l{tutorials/addressbook-fr/part1}{Conception de l'interface utilisateur} |
|
76 \o \l{tutorials/addressbook-fr/part2}{Ajouter des adresses} |
|
77 \o \l{tutorials/addressbook-fr/part3}{Navigation entre les éléments} |
|
78 \o \l{tutorials/addressbook-fr/part4}{éditer et supprimer des adresses} |
|
79 \o \l{tutorials/addressbook-fr/part5}{Ajout d'une fonction de recherche} |
|
80 \o \l{tutorials/addressbook-fr/part6}{Sauvegarde et chargement} |
|
81 \o \l{tutorials/addressbook-fr/part7}{Fonctionnalités avancées} |
|
82 \endlist |
|
83 |
|
84 La petite application que nous développerons ici ne possède pas tous les éléments |
|
85 des interfaces dernier cri, elle va nous permettre d'utiliser les techniques de base |
|
86 utilisées dans les applications plus complexes. |
|
87 |
|
88 Lorsque vous aurez terminé ce tutoriel, nous vous recommandons de poursuivre avec l'exemple |
|
89 "\l{mainwindows/application}{Application}", qui présente une interface simple utilisant |
|
90 les menus et barres d'outils, la barre d'état, etc. |
|
91 |
|
92 */ |
|
93 |
|
94 /*! |
|
95 \page tutorials-addressbook-fr-part1.html |
|
96 \contentspage {Tutoriel "Carnet d'adresses"}{Sommaire} |
|
97 \nextpage {tutorials/addressbook-fr/part2}{Chapitre 2} |
|
98 \example tutorials/addressbook-fr/part1 |
|
99 \title Carnet d'adresses 1 - Conception de l'interface utilisateur |
|
100 |
|
101 La première partie de ce tutoriel traite de la conception d'une interface graphique |
|
102 (GUI) basique, que l'on utilisera pour l'application Carnet d'adresses. |
|
103 |
|
104 La première étape dans la création d'applications graphiques est la conception de |
|
105 l'interface utilisateur. Dans ce chapitre, nous verrons comment créer les labels |
|
106 et champs de saisie nécessaires à l'implementation d'un carnet d'adresses de base. |
|
107 Le résultat attendu est illustré par la capture d'écran ci-dessous. |
|
108 |
|
109 \image addressbook-tutorial-part1-screenshot.png |
|
110 |
|
111 Nous allons avoir besoin de deux objets QLabel, \c nameLabel et \c addressLabel, |
|
112 ainsi que deux champs de saisie: un objet QLineEdit, \c nameLine, et un objet |
|
113 QTextEdit, \c addressText, afin de permettre à l'utilisateur d'entrer le nom d'un |
|
114 contact et son adresse. Les widgets utilisés ainsi que leur placement sont visibles ci-dessous. |
|
115 |
|
116 \image addressbook-tutorial-part1-labeled-screenshot.png |
|
117 |
|
118 Trois fichiers sont nécessaires à l'implémentation de ce carnet d'adresses: |
|
119 |
|
120 \list |
|
121 \o \c{addressbook.h} - le fichier de définition (header) pour la classe \c AddressBook, |
|
122 \o \c{addressbook.cpp} - le fichier source, qui comprend l'implémentation de la classe |
|
123 \c AddressBook |
|
124 \o \c{main.cpp} - le fichier qui contient la méthode \c main() , et |
|
125 une instance de la classe \c AddressBook. |
|
126 \endlist |
|
127 |
|
128 \section1 Programmation en Qt - héritage |
|
129 |
|
130 |
|
131 Lorsque l'on écrit des programmes avec Qt, on a généralement recours à |
|
132 l'héritage depuis des objets Qt, afin d'y ajouter des fonctionnalités. |
|
133 C'est l'un des concepts fondamentaux de la création de widgets personnalisés |
|
134 ou de collections de widgets. Utiliser l'héritage afin de compléter |
|
135 ou modifier le comportement d'un widget présente les avantages suivants: |
|
136 |
|
137 \list |
|
138 \o La possibilité d'implémenter des méthodes virtuelles et des méthodes |
|
139 virtuelles pures pour obtenir exactement ce que l'on souhaite, avec la possibilité |
|
140 d'utiliser l'implémentation de la classe mère si besoin est. |
|
141 \o Cela permet l'encapsulation partielle de l'interface utilisateur dans une classe, |
|
142 afin que les autres parties de l'application n'aient pas à se soucier de chacun des |
|
143 widgets qui forment l'interface utilisateur. |
|
144 \o La classe fille peut être utilisée pour créer de nombreux widgets personnalisés |
|
145 dans une même application ou bibliothèque, et le code de la classe fille peut être |
|
146 réutilisé dans d'autres projets |
|
147 \endlist |
|
148 |
|
149 Comme Qt ne fournit pas de widget standard pour un carnet d'adresses, nous |
|
150 partirons d'une classe de widget Qt standard et y ajouterons des fonctionnalités. |
|
151 La classe \c AddressBook crée dans ce tutoriel peut être réutilisée si on a besoin d'un |
|
152 widget carnet d'adresses basique. |
|
153 |
|
154 |
|
155 \section1 La classe AddressBook |
|
156 |
|
157 Le fichier \l{tutorials/addressbook-fr/part1/addressbook.h}{\c addressbook.h} permet de |
|
158 définir la classe \c AddressBook. |
|
159 |
|
160 On commence par définir \c AddressBook comme une classe fille de QWidget et déclarer |
|
161 un constructeur. On utilise également la macro Q_OBJECT pour indiquer que la classe |
|
162 exploite les fonctionnalités de signaux et slots offertes par Qt ainsi que |
|
163 l'internationalisation, bien que nous ne les utilisions pas à ce stade. |
|
164 |
|
165 \snippet tutorials/addressbook-fr/part1/addressbook.h class definition |
|
166 |
|
167 La classe contient les déclarations de \c nameLine et \c addressText, |
|
168 les instances privées de QLineEdit et QTextEdit mentionnées précédemment. |
|
169 Vous verrez, dans les chapitres à venir que les informations contenues |
|
170 dans \c nameLine et \c addressText sont nécessaires à de nombreuses méthodes |
|
171 du carnet d'adresses. |
|
172 |
|
173 Il n'est pas nécessaire de déclarer les objets QLabel que nous allons utiliser |
|
174 puisque nous n'aurons pas besoin d'y faire référence après leur création. |
|
175 La façon dont Qt gère la parenté des objets est traitée dans la section suivante. |
|
176 |
|
177 La macro Q_OBJECT implémente des fonctionnalités parmi les plus avancées de Qt. |
|
178 Pour le moment, il est bon de voir la macro Q_OBJECT comme un raccourci nous |
|
179 permettant d'utiliser les méthodes \l{QObject::}{tr()} et \l{QObject::}{connect()}. |
|
180 |
|
181 Nous en avons maintenant terminé avec le fichier \c addressbook.h et allons |
|
182 passer à l'implémentation du fichier \c addressbook.cpp. |
|
183 |
|
184 \section1 Implémentation de la classe AddressBook |
|
185 |
|
186 Le constructeur de la classe \c{AddressBook} prend en paramètre un QWidget, \e parent. |
|
187 Par convention, on passe ce paramètre au constructeur de la classe mère. |
|
188 Ce concept de parenté, où un parent peut avoir un ou plusieurs enfants, est utile |
|
189 pour regrouper les Widgets avec Qt. Par exemple, si vous détruisez le parent, |
|
190 tous ses enfants seront détruits égalament. |
|
191 |
|
192 |
|
193 \snippet tutorials/addressbook/part1/addressbook.cpp constructor and input fields |
|
194 |
|
195 à l'intérieur de ce constructeur, on déclare et instancie deux objets locaux |
|
196 QLabel, \c nameLabel et \c addressLabel, de même on instancie \c nameLine et |
|
197 \c addressText. La méthode \l{QObject::tr()}{tr()} renvoie une version traduite |
|
198 de la chaîne de caractères, si elle existe; dans le cas contraire, elle renvoie |
|
199 la chaîne elle même. On peut voir cette méthode comme un marqueur \tt{<insérer |
|
200 la traduction ici>}, permettant de repérer les objets QString à considérer |
|
201 pour traduire une application. Vous remarquerez, dans les chapitres à venir |
|
202 comme dans les \l{Qt Examples}{exemples Qt}, qu'elle est utilisée chaque fois |
|
203 que l'on utilise une chaîne susceptible d'être traduite. |
|
204 |
|
205 Lorsque l'on programme avec Qt, il est utile de savoir comment fonctionnent les |
|
206 agencements ou layouts. Qt fournit trois classes principales de layouts pour |
|
207 contrôler le placement des widgets: QHBoxLayout, QVBoxLayout et QGridLayout. |
|
208 |
|
209 \image addressbook-tutorial-part1-labeled-layout.png |
|
210 |
|
211 On utilise un QGridLayout pour positionner nos labels et champs de saisie de manière |
|
212 structurée. QGridLayout divise l'espace disponible en une grille, et place les |
|
213 widgets dans les cellules que l'on spécifie par les numéros de ligne et de colonne. |
|
214 Le diagramme ci-dessus présente les cellules et la position des widgets, et cette |
|
215 organisation est obtenue à l'aide du code suivant: |
|
216 |
|
217 \snippet tutorials/addressbook/part1/addressbook.cpp layout |
|
218 |
|
219 On remarque que le label \c AddressLabel est positionné en utilisant Qt::AlignTop |
|
220 comme argument optionnel. Ceci est destiné à assurer qu'il ne sera pas centré |
|
221 verticalement dans la cellule (1,0). Pour un aperçu rapide des layouts de Qt, |
|
222 consultez la section \l{Layout Management}. |
|
223 |
|
224 Afin d'installer l'objet layout dans un widget, il faut appeler la méthode |
|
225 \l{QWidget::setLayout()}{setLayout()} du widget en question: |
|
226 |
|
227 \snippet tutorials/addressbook/part1/addressbook.cpp setting the layout |
|
228 |
|
229 Enfin, on initialise le titre du widget à "Simple Address Book" |
|
230 |
|
231 \section1 Exécution de l'application |
|
232 |
|
233 Un fichier séparé, \c main.cpp, est utilisé pour la méthode \c main(). Dans cette |
|
234 fonction, on crée une instance de QApplication, \c app. QApplication se charge de |
|
235 des ressources communes à l'ensemble de l'application, tel que les polices de |
|
236 caractères et le curseur par défaut, ainsi que de l'exécution de la boucle d'évènements. |
|
237 De ce fait, il y a toujours un objet QApplication dans toute application graphique en Qt. |
|
238 |
|
239 \snippet tutorials/addressbook/part1/main.cpp main function |
|
240 |
|
241 On construit un nouveau widget \c AddressBook sur la pile et on invoque |
|
242 sa méthode \l{QWidget::show()}{show()} pour l'afficher. |
|
243 Cependant, le widget ne sera pas visible tant que la boucle d'évènements |
|
244 n'aura pas été lancée. On démarre la boucle d'évènements en appelant la |
|
245 méthode \l{QApplication::}{exec()} de l'application; le résultat renvoyé |
|
246 par cette méthode est lui même utilisé comme valeur de retour pour la méthode |
|
247 \c main(). |
|
248 On comprend maintenant pourquoi \c AddressBook a été créé sur la pile: à la fin |
|
249 du programme, l'objet sort du scope de la fonction \c main() et tous ses widgets enfants |
|
250 sont supprimés, assurant ainsi qu'il n'y aura pas de fuites de mémoire. |
|
251 */ |
|
252 |
|
253 /*! |
|
254 \page tutorials-addressbook-fr-part2.html |
|
255 \previouspage {tutorials/addressbook-fr/part1}{Chapitre 1} |
|
256 \contentspage {Tutoriel "Carnet d'adresses"}{Sommaire} |
|
257 \nextpage {tutorials/addressbook-fr/part3}{Chapitre 3} |
|
258 \example tutorials/addressbook-fr/part2 |
|
259 \title Carnet d'adresses 2 - Ajouter des adresses |
|
260 |
|
261 La prochaine étape pour créer notre carnet d'adresses est d'ajouter un soupçon |
|
262 d'interactivité. |
|
263 |
|
264 \image addressbook-tutorial-part2-add-contact.png |
|
265 |
|
266 Nous allons fournir un bouton que l'utilisateur peut |
|
267 cliquer pour ajouter un nouveau contact. Une structure de données est aussi |
|
268 nécessaire afin de pouvoir stocker les contacts en mémoire. |
|
269 |
|
270 \section1 Définition de la classe AddressBook |
|
271 |
|
272 Maintenant que nous avons mis en place les labels et les champs de saisie, |
|
273 nous ajoutons les boutons pour compléter le processus d'ajout d'un contact. |
|
274 Cela veut dire que notre fichier \c addressbook.h a maintenant trois |
|
275 objets QPushButton et trois slots publics correspondant. |
|
276 |
|
277 \snippet tutorials/addressbook/part2/addressbook.h slots |
|
278 |
|
279 Un slot est une méthode qui répond à un signal. Nous allons |
|
280 voir ce concept en détail lorsque nous implémenterons la classe \c{AddressBook}. |
|
281 Pour une explication détaillée du concept de signal et slot, vous pouvez |
|
282 vous référer au document \l{Signals and Slots}. |
|
283 |
|
284 Les trois objets QPushButton \c addButton, \c submitButton et \c cancelButton |
|
285 sont maintenant inclus dans la déclaration des variables privées, avec |
|
286 \c nameLine et \c addressText du chapitre précédent. |
|
287 |
|
288 \snippet tutorials/addressbook/part2/addressbook.h pushbutton declaration |
|
289 |
|
290 Nous avons besoin d'un conteneur pour stocker les contacts du carnet |
|
291 d'adresses, de façon à pouvoir les énumérer et les afficher. |
|
292 Un objet QMap, \c contacts, est utilisé pour ça, car il permet de stocker |
|
293 des paires clé-valeur: le nom du contact est la \e{clé} et l'adresse du contact |
|
294 est la \e{valeur}. |
|
295 |
|
296 \snippet tutorials/addressbook/part2/addressbook.h remaining private variables |
|
297 |
|
298 Nous déclarons aussi deux objects QString privés: \c oldName et \c oldAddress. |
|
299 Ces objets sont nécessaires pour conserver le nom et l'adresse du dernier contact |
|
300 affiché avant que l'utilisateur ne clique sur le bouton "Add". Grâce à ces variables |
|
301 si l'utilisateur clique sur "Cancel", il est possible de revenir |
|
302 à l'affichage du dernier contact. |
|
303 |
|
304 \section1 Implémentation de la classe AddressBook |
|
305 |
|
306 Dans le constructeur de \c AddressBook, \c nameLine et |
|
307 \c addressText sont mis en mode lecture seule, de façon à autoriser l'affichage |
|
308 mais pas la modification du contact courant. |
|
309 |
|
310 \dots |
|
311 \snippet tutorials/addressbook/part2/addressbook.cpp setting readonly 1 |
|
312 \dots |
|
313 \snippet tutorials/addressbook/part2/addressbook.cpp setting readonly 2 |
|
314 |
|
315 Ensuite, nous instancions les boutons \c addButton, \c submitButton, et |
|
316 \c cancelButton. |
|
317 |
|
318 \snippet tutorials/addressbook/part2/addressbook.cpp pushbutton declaration |
|
319 |
|
320 Le bouton \c addButton est affiché en invoquant la méthode \l{QPushButton::show()} |
|
321 {show()}, tandis que \c submitButton et \c cancelButton sont cachés en invoquant |
|
322 \l{QPushButton::hide()}{hide()}. Ces deux boutons ne seront affichés que lorsque |
|
323 l'utilisateur cliquera sur "Add", et ceci est géré par la méthode \c addContact() |
|
324 décrite plus loin. |
|
325 |
|
326 \snippet tutorials/addressbook/part2/addressbook.cpp connecting signals and slots |
|
327 |
|
328 Nous connectons le signal \l{QPushButton::clicked()}{clicked()} de chaque bouton |
|
329 au slot qui gèrera l'action. |
|
330 L'image ci-dessous illustre ceci: |
|
331 |
|
332 \image addressbook-tutorial-part2-signals-and-slots.png |
|
333 |
|
334 Ensuite, nous arrangeons proprement les boutons sur la droite du widget |
|
335 AddressBook, et nous utilisons un QVBoxLayout pour les aligner verticalement. |
|
336 |
|
337 \snippet tutorials/addressbook/part2/addressbook.cpp vertical layout |
|
338 |
|
339 La methode \l{QBoxLayout::addStretch()}{addStretch()} est utilisée pour |
|
340 assurer que les boutons ne sont pas répartis uniformément, mais regroupés |
|
341 dans la partie supperieure du widget. La figure ci-dessous montre la différence |
|
342 si \l{QBoxLayout::addStretch()}{addStretch()} est utilisé ou pas. |
|
343 |
|
344 \image addressbook-tutorial-part2-stretch-effects.png |
|
345 |
|
346 Ensuite nous ajoutons \c buttonLayout1 à \c mainLayout, en utilisant |
|
347 \l{QGridLayout::addLayout()}{addLayout()}. Ceci nous permet d'imbriquer les |
|
348 mises en page puisque \c buttonLayout1 est maintenant un enfant de \c mainLayout. |
|
349 |
|
350 \snippet tutorials/addressbook/part2/addressbook.cpp grid layout |
|
351 |
|
352 Les coordonnées du layout global ressemblent maintenant à ça: |
|
353 |
|
354 \image addressbook-tutorial-part2-labeled-layout.png |
|
355 |
|
356 Dans la méthode \c addContact(), nous stockons les détails du dernier |
|
357 contact affiché dans \c oldName et \c oldAddress. Ensuite, nous |
|
358 vidons ces champs de saisie et nous désactivons le mode |
|
359 lecture seule. Le focus est placé sur \c nameLine et on affiche |
|
360 \c submitButton et \c cancelButton. |
|
361 |
|
362 \snippet tutorials/addressbook/part2/addressbook.cpp addContact |
|
363 |
|
364 La méthode \c submitContact() peut être divisée en trois parties: |
|
365 |
|
366 \list 1 |
|
367 \o Nous extrayons les détails du contact depuis \c nameLine et \c addressText |
|
368 et les stockons dans des objets QString. Nous les validons pour s'assurer |
|
369 que l'utilisateur n'a pas cliqué sur "Add" avec des champs de saisie |
|
370 vides; sinon un message est affiché avec QMessageBox pour rappeller à |
|
371 l'utilisateur que les deux champs doivent être complétés. |
|
372 |
|
373 \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part1 |
|
374 |
|
375 \o Ensuite, nous vérifions si le contact existe déjà. Si aucun contacts |
|
376 existant n'entre en conflit avec le nouveau, nous l'ajoutons à |
|
377 \c contacts et nous affichons un QMessageBox pour informer l'utilisateur |
|
378 que le contact a été ajouté. |
|
379 |
|
380 \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part2 |
|
381 |
|
382 Si le contact existe déjà, nous affichons un QMessageBox pour informer |
|
383 l'utilisateur du problème. |
|
384 Notre objet \c contacts est basé sur des paires clé-valeur formés par |
|
385 le nom et l'adresse, nous voulons nous assurer que la \e clé est unique. |
|
386 |
|
387 \o Une fois que les deux vérifications précédentes ont été traitées, |
|
388 nous restaurons les boutons à leur état normal à l'aide du code |
|
389 suivant: |
|
390 |
|
391 \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part3 |
|
392 |
|
393 \endlist |
|
394 |
|
395 La capture d'écran ci-dessous montre l'affichage fournit par un objet |
|
396 QMessageBox, utilisé ici pour afficher un message d'information |
|
397 à l'utilisateur: |
|
398 |
|
399 \image addressbook-tutorial-part2-add-successful.png |
|
400 |
|
401 La méthode \c cancel() restaure les détails du dernier contact, active |
|
402 \c addButton, et cache \c submitButton et \c cancelButton. |
|
403 |
|
404 \snippet tutorials/addressbook/part2/addressbook.cpp cancel |
|
405 |
|
406 L'idée générale pour augmenter la flexibilité lors de l'ajout d'un |
|
407 contact est de donner la possiblité de cliquer sur "Add" |
|
408 ou "Cancel" à n'importe quel moment. |
|
409 L'organigramme ci-dessous reprend l'ensemble des interactions dévelopées |
|
410 jusqu'ici: |
|
411 |
|
412 \image addressbook-tutorial-part2-add-flowchart.png |
|
413 */ |
|
414 |
|
415 /*! |
|
416 \page tutorials-addressbook-fr-part3.html |
|
417 \previouspage {tutorials/addressbook-fr/part2}{Chapitre 2} |
|
418 \contentspage {Tutoriel "Carnet d'adresses"}{Sommaire} |
|
419 \nextpage {tutorials/addressbook-fr/part4}{Chapitre 4} |
|
420 \example tutorials/addressbook-fr/part3 |
|
421 \title Carnet d'adresses 3 - Navigation entre les éléments |
|
422 |
|
423 L'application "Carnet d'adresses" est maintenant à moitié terminée. Il |
|
424 nous faut maintenant ajouter quelques fonctions pour naviguer entre |
|
425 les contacts. Avant de commencer, il faut se décider sur le type de structure de |
|
426 données le plus approprié pour stocker les contacts. |
|
427 |
|
428 Dans le chapitre 2, nous avons utilisé un QMap utilisant des paires clé-valeur, |
|
429 avec le nom du contact comme \e clé, et l'adresse du contact comme \e valeur. |
|
430 Cela fonctionnait bien jusqu'ici, mais pour ajouter la navigation entre les |
|
431 entrées, quelques améliorations sont nécessaires. |
|
432 |
|
433 Nous améliorerons le QMap en le faisant ressembler à une structure de données |
|
434 similaire à une liste liée, où tous les éléments sont connectés, y compris |
|
435 le premier et le dernier élément. La figure ci-dessous illustre cette structure |
|
436 de donnée. |
|
437 |
|
438 \image addressbook-tutorial-part3-linkedlist.png |
|
439 |
|
440 \section1 Définition de la classe AddressBook |
|
441 |
|
442 Pour ajouter les fonctions de navigation au carnet d'adresses, nous avons |
|
443 besoin de deux slots supplémentaires dans notre classe \c AddressBook: |
|
444 \c next() et \c previous(). Ceux-ci sont ajoutés au fichier addressbook.h: |
|
445 |
|
446 \snippet tutorials/addressbook/part3/addressbook.h navigation functions |
|
447 |
|
448 Nous avons aussi besoin de deux nouveaux objets QPushButton, nous ajoutons |
|
449 donc les variables privées \c nextButton et \c previousButton. |
|
450 |
|
451 \snippet tutorials/addressbook/part3/addressbook.h navigation pushbuttons |
|
452 |
|
453 \section1 Implémentation de la classe AddressBook |
|
454 |
|
455 A l'intérieur du constructeur de \c AddressBook, dans \c addressbook.cpp, nous |
|
456 instancions \c nextButton et \c previousButton et nous les désactivons |
|
457 par défaut. Nous faisons ceci car la navigation ne doit être activée |
|
458 que lorsqu'il y a plus d'un contact dans le carnet d'adresses. |
|
459 |
|
460 \snippet tutorials/addressbook/part3/addressbook.cpp navigation pushbuttons |
|
461 |
|
462 Nous connectons alors ces boutons à leur slots respectifs: |
|
463 |
|
464 \snippet tutorials/addressbook/part3/addressbook.cpp connecting navigation signals |
|
465 |
|
466 L'image ci-dessous montre l'interface utilisateur que nous allons créer. |
|
467 Remarquez que cela ressemble de plus en plus à l'interface du programme |
|
468 complet. |
|
469 |
|
470 \image addressbook-tutorial-part3-screenshot.png |
|
471 |
|
472 Nous suivons les conventions pour les fonctions \c next() et \c previous() |
|
473 en plaçant \c nextButton à droite et \c previousButton à gauche. Pour |
|
474 faire cette mise en page intuitive, nous utilisons un QHBoxLayout pour |
|
475 placer les widgets côte à côte: |
|
476 |
|
477 \snippet tutorials/addressbook/part3/addressbook.cpp navigation layout |
|
478 |
|
479 L'objet QHBoxLayout, \c buttonLayout2, est ensuite ajouté à \c mainLayout. |
|
480 |
|
481 \snippet tutorials/addressbook/part3/addressbook.cpp adding navigation layout |
|
482 |
|
483 La figure ci-dessous montre les systèmes de coordonnées pour les widgets du |
|
484 \c mainLayout. |
|
485 \image addressbook-tutorial-part3-labeled-layout.png |
|
486 |
|
487 Dans notre méthode \c addContact(), nous avons desactivé ces boutons |
|
488 pour être sûr que l'utilisateur n'utilise pas la navigation lors de |
|
489 l'ajout d'un contact. |
|
490 |
|
491 \snippet tutorials/addressbook/part3/addressbook.cpp disabling navigation |
|
492 |
|
493 Dans notre méthode \c submitContact(), nous activons les boutons de |
|
494 navigation, \c nextButton et \c previousButton, en fonction de la |
|
495 taille de \c contacts. Commen mentionné plus tôt, la navigation n'est |
|
496 activée que si il y a plus d'un contact dans le carnet d'adresses. |
|
497 Les lignes suivantes montrent comment faire cela: |
|
498 |
|
499 \snippet tutorials/addressbook/part3/addressbook.cpp enabling navigation |
|
500 |
|
501 Nous incluons aussi ces lignes de code dans le bouton \c cancel(). |
|
502 |
|
503 Souvenez vous que nous voulons émuler une liste-liée ciruculaire à |
|
504 l'aide de l'objet QMap, \c contacts. Pour faire cela, nous obtenons un itérateur |
|
505 sur \c contact dans la méthode \c next(), et ensuite: |
|
506 |
|
507 \list |
|
508 \o Si l'itérateur n'est pas à la fin de \c contacts, nous l'incrémentons |
|
509 \o Si l'itérateur est à la fin de \c contacts, nous changeons sa position |
|
510 jusqu'au début de \c contacts. Cela donne l'illusion que notre QMap |
|
511 fonctionne comme une liste circulaire. |
|
512 \endlist |
|
513 |
|
514 \snippet tutorials/addressbook/part3/addressbook.cpp next() function |
|
515 |
|
516 Une fois que nous avons itéré jusqu'à l'objet recherché dans \c contacts, |
|
517 nous affichons son contenu sur \c nameLine et \c addressText. |
|
518 |
|
519 De la même façon, pour la méthode \c previous(), nous obtenons un |
|
520 itérateur sur \c contacts et ensuite: |
|
521 |
|
522 \list |
|
523 \o Si l'itérateur est à la fin de \c contacts, on réinitialise |
|
524 l'affichage et on retourne. |
|
525 \o Si l'itérateur est au début de \c contacts, on change sa |
|
526 position jusqu'à la fin |
|
527 \o Ensuite, on décrémente l'itérateur |
|
528 \endlist |
|
529 |
|
530 \snippet tutorials/addressbook/part3/addressbook.cpp previous() function |
|
531 |
|
532 à nouveau, nous affichons le contenu de l'objet courant dans \c contacts. |
|
533 |
|
534 */ |
|
535 |
|
536 /*! |
|
537 |
|
538 \page tutorials-addressbook-fr-part4.html |
|
539 \previouspage {tutorials/addressbook-fr/part3}{Chapitre 3} |
|
540 \contentspage {Tutoriel "Carnet d'adresses"}{Sommaire} |
|
541 \nextpage {tutorials/addressbook-fr/part5}{Chapitre 5} |
|
542 \example tutorials/addressbook-fr/part4 |
|
543 \title Carnet d'Adresses 4 - éditer et supprimer des adresses |
|
544 |
|
545 |
|
546 Dans ce chapitre, nous verrons comment modifier les données des contacts |
|
547 contenus dans l'application carnet d'adresses. |
|
548 |
|
549 |
|
550 \image addressbook-tutorial-screenshot.png |
|
551 |
|
552 Nous avons maintenant un carnet d'adresses qui ne se contente pas de |
|
553 lister des contacts de façon ordonnée, mais permet également la |
|
554 navigation. Il serait pratique d'inclure des fonctions telles qu'éditer et |
|
555 supprimer, afin que les détails associés à un contact puissent être |
|
556 modifiés lorsque c'est nécessaire. Cependant, cela requiert une légère |
|
557 modification, sous la forme d'énumérations. Au chapitre précédent, nous avions deux |
|
558 modes: \c {AddingMode} et \c {NavigationMode}, mais ils n'étaient pas |
|
559 définis en tant qu'énumérations. Au lieu de ça, on activait et désactivait les |
|
560 boutons correspondants manuellement, au prix de multiples redondances dans |
|
561 le code. |
|
562 |
|
563 Dans ce chapitre, on définit l'énumération \c Mode avec trois valeurs possibles. |
|
564 |
|
565 \list |
|
566 \o \c{NavigationMode}, |
|
567 \o \c{AddingMode}, et |
|
568 \o \c{EditingMode}. |
|
569 \endlist |
|
570 |
|
571 \section1 Définition de la classe AddressBook |
|
572 |
|
573 Le fichier \c addressbook.h est mis a jour pour contenir l'énumération \c Mode : |
|
574 |
|
575 \snippet tutorials/addressbook/part4/addressbook.h Mode enum |
|
576 |
|
577 On ajoute également deux nouveaux slots, \c editContact() et |
|
578 \c removeContact(), à notre liste de slots publics. |
|
579 |
|
580 \snippet tutorials/addressbook/part4/addressbook.h edit and remove slots |
|
581 |
|
582 Afin de basculer d'un mode à l'autre, on introduit la méthode |
|
583 \c updateInterface() pour contrôller l'activation et la désactivation de |
|
584 tous les objets QPushButton. On ajoute également deux nouveaux boutons, |
|
585 \c editButton et \c removeButton, pour les fonctions d'édition |
|
586 et de suppression mentionnées plus haut. |
|
587 |
|
588 \snippet tutorials/addressbook/part4/addressbook.h updateInterface() declaration |
|
589 \dots |
|
590 \snippet tutorials/addressbook/part4/addressbook.h buttons declaration |
|
591 \dots |
|
592 \snippet tutorials/addressbook/part4/addressbook.h mode declaration |
|
593 |
|
594 Enfin, on déclare \c currentMode pour garder une trace du mode |
|
595 actuellement utilisé. |
|
596 |
|
597 \section1 Implémentation de la classe AddressBook |
|
598 |
|
599 Il nous faut maintenant implémenter les fonctionnalités de changement de |
|
600 mode de l'application carnet d'adresses. Les boutons \c editButton et |
|
601 \c removeButton sont instanciés et désactivés par défaut, puisque le |
|
602 carnet d'adresses démarre sans aucun contact en mémoire. |
|
603 |
|
604 \snippet tutorials/addressbook/part4/addressbook.cpp edit and remove buttons |
|
605 |
|
606 Ces boutons sont ensuite connectés à leurs slots respectifs, |
|
607 \c editContact() et \c removeContact(), avant d'être ajoutés à |
|
608 \c buttonLayout1. |
|
609 |
|
610 \snippet tutorials/addressbook/part4/addressbook.cpp connecting edit and remove |
|
611 \dots |
|
612 \snippet tutorials/addressbook/part4/addressbook.cpp adding edit and remove to the layout |
|
613 |
|
614 La methode \c editContact() place les anciens détails du contact dans |
|
615 \c oldName et \c oldAddress, avant de basculer vers le mode |
|
616 \c EditingMode. Dans ce mode, les boutons \c submitButton et |
|
617 \c cancelButton sont tous deux activés, l'utilisateur peut par conséquent |
|
618 modifier les détails du contact et cliquer sur l'un de ces deux boutons |
|
619 par la suite. |
|
620 |
|
621 \snippet tutorials/addressbook/part4/addressbook.cpp editContact() function |
|
622 |
|
623 La méthode \c submitContact() a été divisée en deux avec un bloc |
|
624 \c{if-else}. On teste \c currentMode pour voir si le mode courant est |
|
625 \c AddingMode. Si c'est le cas, on procède à l'ajout. |
|
626 |
|
627 \snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function beginning |
|
628 \dots |
|
629 \snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function part1 |
|
630 |
|
631 Sinon, on s'assure que \c currentMode est en \c EditingMode. Si c'est le |
|
632 cas, on compare \c oldName et \c name. Si le nom a changé, on supprime |
|
633 l'ancien contact de \c contacts et on insère le contact mis a jour. |
|
634 |
|
635 \snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function part2 |
|
636 |
|
637 Si seule l'adresse a changé (i.e. \c oldAddress n'est pas identique à |
|
638 \c address), on met à jour l'adresse du contact. Enfin on règle |
|
639 \c currentMode à \c NavigationMode. C'est une étape importante puisque |
|
640 c'est cela qui réactive tous les boutons désactivés. |
|
641 |
|
642 Afin de retirer un contact du carnet d'adresses, on implémente la méthode |
|
643 \c removeContact(). Cette méthode vérifie que le contact est présent dans |
|
644 \c contacts. |
|
645 |
|
646 \snippet tutorials/addressbook/part4/addressbook.cpp removeContact() function |
|
647 |
|
648 Si c'est le cas, on affiche une boîte de dialogue QMessageBox, demandant |
|
649 confirmation de la suppression à l'utilisateur. Une fois la confirmation |
|
650 effectuée, on appelle \c previous(), afin de s'assurer que l'interface |
|
651 utilisateur affiche une autre entrée, et on supprime le contact en |
|
652 utilisant le méthode \l{QMap::remove()}{remove()} de \l{QMap}. Dans un |
|
653 souci pratique, on informe l'utilisateur de la suppression par le biais |
|
654 d'une autre QMessageBox. Les deux boîtes de dialogue utilisées dans cette |
|
655 méthode sont représentées ci-dessous. |
|
656 |
|
657 \image addressbook-tutorial-part4-remove.png |
|
658 |
|
659 \section2 Mise à jour de l'Interface utilisateur |
|
660 |
|
661 On a évoqué plus haut la méthode \c updateInterface() comme moyen |
|
662 d'activer et de désactiver les différents boutons de l'interface en |
|
663 fonction du mode. Cette méthode met à jour le mode courant selon |
|
664 l'argument \c mode qui lui est passé, en l'assignant à \c currentMode, |
|
665 avant de tester sa valeur. |
|
666 |
|
667 Chacun des boutons est ensuite activé ou désactivé, en fonction du mode. |
|
668 Le code source pour les cas \c AddingMode et \c EditingMode est visible |
|
669 ci-dessous: |
|
670 |
|
671 \snippet tutorials/addressbook/part4/addressbook.cpp update interface() part 1 |
|
672 |
|
673 Dans le cas de \c NavigationMode, en revanche, des tests conditionnels |
|
674 sont passés en paramètre de QPushButton::setEnabled(). Ceci permet de |
|
675 s'assurer que les boutons \c editButton et \c removeButton ne sont activés |
|
676 que s'il existe au moins un contact dans le carnet d'adresses; |
|
677 \c nextButton et \c previousButton ne sont activés que lorsqu'il existe |
|
678 plus d'un contact dans le carnet d'adresses. |
|
679 |
|
680 \snippet tutorials/addressbook/part4/addressbook.cpp update interface() part 2 |
|
681 |
|
682 En effectuant les opérations de réglage du mode et de mise à jour de |
|
683 l'interface utilisateur au sein de la même méthode, on est à l'abri de |
|
684 l'éventualité où l'interface utilisateur se "désynchronise" de l'état |
|
685 interne de l'application. |
|
686 |
|
687 */ |
|
688 |
|
689 /*! |
|
690 \page tutorials-addressbook-fr-part5.html |
|
691 \previouspage {tutorials/addressbook-fr/part4}{Chapitre 4} |
|
692 \contentspage {Tutoriel "Carnet d'adresses"}{Sommaire} |
|
693 \nextpage {tutorials/addressbook-fr/part6}{Chapitre 6} |
|
694 \example tutorials/addressbook-fr/part5 |
|
695 \title Carnet d'adresse 5 - Ajout d'une fonction de recherche |
|
696 |
|
697 Dans ce chapitre, nous allons voir les possibilités pour rechercher |
|
698 des contacts dans le carnet d'adresse. |
|
699 |
|
700 \image addressbook-tutorial-part5-screenshot.png |
|
701 |
|
702 Plus nous ajoutons des contacts dans l'application, plus |
|
703 il devient difficile de naviguer avec les boutons \e Next et \e Previous. |
|
704 Dans ce cas, une fonction de recherche serait plus efficace pour rechercher |
|
705 les contacts. |
|
706 La capture d'écran ci-dessus montre le bouton de recherche \e Find et sa position |
|
707 dans le paneau de bouton. |
|
708 |
|
709 Lorsque l'utilisateur clique sur le bouton \e Find, il est courant d'afficher |
|
710 une boîte de dialogue qui demande à l'utilisateur d'entrer un nom de contact. |
|
711 Qt fournit la classe QDialog, que nous sous-classons dans ce chapitre pour |
|
712 implémenter la class \c FindDialog. |
|
713 |
|
714 \section1 Définition de la classe FindDialog |
|
715 |
|
716 \image addressbook-tutorial-part5-finddialog.png |
|
717 |
|
718 Pour sous-classer QDialog, nous commençons par inclure le header de |
|
719 QDialog dans le fichier \c finddialog.h. De plus, nous déclarons les |
|
720 classes QLineEdit et QPushButton car nous utilisons ces widgets dans |
|
721 notre classe dialogue. |
|
722 |
|
723 Tout comme dans la classe \c AddressBook, la classe \c FindDialog utilise |
|
724 la macro Q_OBJECT et son constructeur est défini de façon à accepter |
|
725 un QWidget parent, même si cette boîte de dialogue sera affichée dans une |
|
726 fenêtre séparée. |
|
727 |
|
728 \snippet tutorials/addressbook/part5/finddialog.h FindDialog header |
|
729 |
|
730 Nous définissons la méthode publique \c getFindText() pour être utilisée |
|
731 par les classes qui instancient \c FindDialog, ce qui leur permet d'obtenir |
|
732 le texte entré par l'utilisateur. Un slot public, \c findClicked(), est |
|
733 défini pour prendre en charge le texte lorsque l'utilisateur clique sur |
|
734 le bouton \gui Find. |
|
735 |
|
736 Finalement, nous définissons les variables privées \c findButton, |
|
737 \c lineEdit et \c findText, qui correspondent respectivement au bouton |
|
738 \gui Find, au champ de texte dans lequel l'utilisateur tape le texte |
|
739 à rechercher, et à une variable interne stockant le texte pour une |
|
740 utilisation ultérieure. |
|
741 |
|
742 \section1 Implémentation de la classe FindDialog |
|
743 |
|
744 Dans le constructeur de \c FindDialog, nous instancions les objets des |
|
745 variables privées \c lineEdit, \c findButton et \c findText. Nous utilisons ensuite |
|
746 un QHBoxLayout pour positionner les widgets. |
|
747 |
|
748 \snippet tutorials/addressbook/part5/finddialog.cpp constructor |
|
749 |
|
750 Nous mettons en place la mise en page et le titre de la fenêtre, et |
|
751 nous connectons les signaux aux slots. Remarquez que le signal |
|
752 \l{QPushButton::clicked()}{clicked()} de \c{findButton} est connecté |
|
753 à \c findClicked() et \l{QDialog::accept()}{accept()}. Le slot |
|
754 \l{QDialog::accept()}{accept()} fourni par le QDialog ferme |
|
755 la boîte de dialogue et lui donne le code de retour \l{QDialog::}{Accepted}. |
|
756 Nous utilisons cette fonction pour aider la méthode \c findContact() de la classe |
|
757 \c{AddressBook} à savoir si l'objet \c FindDialog a été fermé. Ceci sera |
|
758 expliqué plus loin lorsque nous verrons la méthode \c findContact(). |
|
759 |
|
760 \image addressbook-tutorial-part5-signals-and-slots.png |
|
761 |
|
762 Dans \c findClicked(), nous validons le champ de texte pour nous |
|
763 assurer que l'utilisateur n'a pas cliqué sur le bouton \gui Find sans |
|
764 avoir entré un nom de contact. Ensuite, nous stockons le texte du champ |
|
765 d'entrée \c lineEdit dans \c findText. Et finalement nous vidons le |
|
766 contenu de \c lineEdit et cachons la boîte de dialogue. |
|
767 |
|
768 \snippet tutorials/addressbook/part5/finddialog.cpp findClicked() function |
|
769 |
|
770 La variable \c findText a un accesseur publique associé: \c getFindText(). |
|
771 Étant donné que nous ne modifions \c findText directement que dans le |
|
772 constructeur et la méthode \c findClicked(), nous ne créons pas |
|
773 de manipulateurs associé à \c getFindText(). |
|
774 Puisque \c getFindText() est publique, les classes instanciant et |
|
775 utilisant \c FindDialog peuvent toujours accéder à la chaîne de |
|
776 caractères que l'utilisateur a entré et accepté. |
|
777 |
|
778 \snippet tutorials/addressbook/part5/finddialog.cpp getFindText() function |
|
779 |
|
780 \section1 Définition de la classe AddressBook |
|
781 |
|
782 Pour utiliser \c FindDialog depuis la classe \c AddressBook, nous |
|
783 incluons \c finddialog.h dans le fichier \c addressbook.h. |
|
784 |
|
785 \snippet tutorials/addressbook/part5/addressbook.h include finddialog's header |
|
786 |
|
787 Jusqu'ici, toutes les fonctionnalités du carnet d'adresses ont un |
|
788 QPushButton et un slot correspondant. De la même façon, pour la |
|
789 fonctionnalité \gui Find, nous avons \c findButton et \c findContact(). |
|
790 |
|
791 Le \c findButton est déclaré comme une variable privée et la |
|
792 méthode \c findContact() est déclarée comme un slot public. |
|
793 |
|
794 \snippet tutorials/addressbook/part5/addressbook.h findContact() declaration |
|
795 \dots |
|
796 \snippet tutorials/addressbook/part5/addressbook.h findButton declaration |
|
797 |
|
798 Finalement, nous déclarons la variable privée \c dialog que nous allons |
|
799 utiliser pour accéder à une instance de \c FindDialog. |
|
800 |
|
801 \snippet tutorials/addressbook/part5/addressbook.h FindDialog declaration |
|
802 |
|
803 Une fois que nous avons instancié la boîte de dialogue, nous voulons l'utiliser |
|
804 plus qu'une fois. Utiliser une variable privée nous permet d'y référer |
|
805 à plus d'un endroit dans la classe. |
|
806 |
|
807 \section1 Implémentation de la classe AddressBook |
|
808 |
|
809 Dans le constructeur de \c AddressBook, nous instancions nos objets privés, |
|
810 \c findbutton et \c findDialog: |
|
811 |
|
812 \snippet tutorials/addressbook/part5/addressbook.cpp instantiating findButton |
|
813 \dots |
|
814 \snippet tutorials/addressbook/part5/addressbook.cpp instantiating FindDialog |
|
815 |
|
816 Ensuite, nous connectons le signal \l{QPushButton::clicked()}{clicked()} de |
|
817 \c{findButton} à \c findContact(). |
|
818 |
|
819 \snippet tutorials/addressbook/part5/addressbook.cpp signals and slots for find |
|
820 |
|
821 Maintenant, tout ce qui manque est le code de notre méthode \c findContact(): |
|
822 |
|
823 \snippet tutorials/addressbook/part5/addressbook.cpp findContact() function |
|
824 |
|
825 Nous commençons par afficher l'instance de \c FindDialog, \c dialog. |
|
826 L'utilisateur peut alors entrer le nom du contact à rechercher. Lorsque |
|
827 l'utilisateur clique sur le bouton \c findButton, la boîte de dialogue est |
|
828 masquée et le code de retour devient QDialog::Accepted. Ce code de retour |
|
829 vient remplir la condition du premier if. |
|
830 |
|
831 Ensuite, nous extrayons le texte que nous utiliserons pour la recherche, |
|
832 il s'agit ici de \c contactName obtenu à l'aide de la méthode \c getFindText() |
|
833 de \c FindDialog. Si le contact existe dans le carnet d'adresse, nous |
|
834 l'affichons directement. Sinon, nous affichons le QMessageBox suivant pour |
|
835 indiquer que la recherche à échouée. |
|
836 |
|
837 \image addressbook-tutorial-part5-notfound.png |
|
838 */ |
|
839 |
|
840 /*! |
|
841 \page tutorials-addressbook-part6.html |
|
842 \previouspage {tutorials/addressbook-fr/part5}{Chapitre 5} |
|
843 \contentspage {Tutoriel "Carnet d'adresses"}{Sommaire} |
|
844 \nextpage {tutorials/addressbook-fr/part7}{Chapitre 7} |
|
845 \example tutorials/addressbook-fr/part6 |
|
846 \title Carnet d'Adresses 6 - Sauvegarde et chargement |
|
847 |
|
848 Ce chapitre couvre les fonctionnalités de gestion des fichiers de Qt que |
|
849 l'on utilise pour écrire les procédures de sauvegarde et chargement pour |
|
850 l'application carnet d'adresses. |
|
851 |
|
852 \image addressbook-tutorial-part6-screenshot.png |
|
853 |
|
854 Bien que la navigation et la recherche de contacts soient des |
|
855 fonctionnalités importantes, notre carnet d'adresses ne sera pleinement |
|
856 utilisable qu'une fois que l'on pourra sauvegarder les contacts existants |
|
857 et les charger à nouveau par la suite. |
|
858 Qt fournit de nombreuses classes pour gérer les \l{Input/Output and |
|
859 Networking}{entrées et sorties}, mais nous avons choisi de nous contenter d'une |
|
860 combinaison de deux classes simples à utiliser ensemble: QFile et QDataStream. |
|
861 |
|
862 Un objet QFile représente un fichier sur le disque qui peut être lu, et |
|
863 dans lequel on peut écrire. QFile est une classe fille de la classe plus |
|
864 générique QIODevice, qui peut représenter différents types de |
|
865 périphériques. |
|
866 |
|
867 Un objet QDataStream est utilisé pour sérialiser des données binaires |
|
868 dans le but de les passer à un QIODevice pour les récupérer dans le |
|
869 futur. Pour lire ou écrire dans un QIODevice, il suffit d'ouvrir le |
|
870 flux, avec le périphérique approprié en paramètre, et d'y lire ou |
|
871 écrire. |
|
872 |
|
873 \section1 Définition de la classe AddressBook |
|
874 |
|
875 On déclare deux slots publics, \c saveToFile() et \c loadFromFile(), |
|
876 ainsi que deux objets QPushButton, \c loadButton et \c saveButton. |
|
877 |
|
878 \snippet tutorials/addressbook/part6/addressbook.h save and load functions declaration |
|
879 \dots |
|
880 \snippet tutorials/addressbook/part6/addressbook.h save and load buttons declaration |
|
881 |
|
882 \section1 Implémentation de la classe AddressBook |
|
883 |
|
884 Dans notre constructeur, on instancie \c loadButton et \c saveButton. |
|
885 Idéalement, l'interface serait plus conviviale avec des boutons |
|
886 affichant "Load contacts from a file" et "Save contacts to a file". Mais |
|
887 compte tenu de la dimension des autres boutons, on initialise les labels |
|
888 des boutons à \gui{Load...} et \gui{Save...}. Heureusement, Qt offre une |
|
889 façon simple d'ajouter des info-bulles avec |
|
890 \l{QWidget::setToolTip()}{setToolTip()}, et nous l'exploitons de la façon |
|
891 suivante pour nos boutons: |
|
892 |
|
893 \snippet tutorials/addressbook/part6/addressbook.cpp tooltip 1 |
|
894 \dots |
|
895 \snippet tutorials/addressbook/part6/addressbook.cpp tooltip 2 |
|
896 |
|
897 Bien qu'on ne cite pas le code correspondant ici, nous ajoutons ces deux boutons au |
|
898 layout de droite, \c button1Layout, comme pour les fonctionnalités précédentes, et |
|
899 nous connectons leurs signaux |
|
900 \l{QPushButton::clicked()}{clicked()} à leurs slots respectifs. |
|
901 |
|
902 Pour la sauvegarde, on commence par récupérer le nom de fichier |
|
903 \c fileName, en utilisant QFileDialog::getSaveFileName(). C'est une |
|
904 méthode pratique fournie par QFileDialog, qui ouvre une boîte de |
|
905 dialogue modale et permet à l'utilisateur d'entrer un nom de fichier ou |
|
906 de choisir un fichier \c{.abk} existant. Les fichiers \c{.abk} |
|
907 correspondent à l'extension choisie pour la sauvegarde des contacts de |
|
908 notre carnet d'adresses. |
|
909 |
|
910 \snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part1 |
|
911 |
|
912 La boîte de dialogue affichée est visible sur la capture d'écran ci- |
|
913 dessous. |
|
914 |
|
915 \image addressbook-tutorial-part6-save.png |
|
916 |
|
917 Si \c fileName n'est pas vide, on crée un objet QFile, \c file, à partir |
|
918 de \c fileName. QFile fonctionne avec QDataStream puisqu'il dérive de |
|
919 QIODevice. |
|
920 |
|
921 Ensuite, on essaie d'ouvrir le fichier en écriture, ce qui correspond au |
|
922 mode \l{QIODevice::}{WriteOnly}. Si cela échoue, on en informe |
|
923 l'utilisateur avec une QMessageBox. |
|
924 |
|
925 \snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part2 |
|
926 |
|
927 Dans le cas contraire, on instancie un objet QDataStream, \c out, afin |
|
928 d'écrire dans le fichier ouvert. QDataStream nécessite que la même |
|
929 version de flux soit utilisée pour la lecture et l'écriture. On s'assure |
|
930 que c'est le cas en spécifiant explicitement d'utiliser la |
|
931 \l{QDataStream::Qt_4_5}{version introduite avec Qt 4.5} avant de |
|
932 sérialiser les données vers le fichier \c file. |
|
933 |
|
934 \snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part3 |
|
935 |
|
936 Pour le chargement, on récupère également \c fileName en utilisant |
|
937 QFileDialog::getOpenFileName(). Cette méthode est l'homologue de |
|
938 QFileDialog::getSaveFileName() et affiche également une boîte de |
|
939 dialogue modale permettant à l'utilisateur d'entrer un nom de fichier ou |
|
940 de selectionner un fichier \c{.abk} existant, afin de le charger dans le |
|
941 carnet d'adresses. |
|
942 |
|
943 \snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part1 |
|
944 |
|
945 Sous Windows, par exemple, cette méthode affiche une boîte de dialogue |
|
946 native pour la sélection de fichier, comme illustré sur la capture |
|
947 d'écran suivante: |
|
948 |
|
949 \image addressbook-tutorial-part6-load.png |
|
950 |
|
951 Si \c fileName n'est pas vide, on utilise une fois de plus un objet |
|
952 QFile, \c file, et on tente de l'ouvrir en lecture, avec le mode |
|
953 \l{QIODevice::}{ReadOnly}. De même que précédemment dans notre |
|
954 implémentation de \c saveToFile(), si cette tentative s'avère |
|
955 infructueuse, on en informe l'utilisateur par le biais d'une |
|
956 QMessageBox. |
|
957 |
|
958 \snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part2 |
|
959 |
|
960 Dans le cas contraire, on instancie un objet QDataStream, \c in, en |
|
961 spécifiant la version à utiliser comme précédemment, et on lit les |
|
962 informations sérialisées vers la structure de données \c contacts. Notez |
|
963 qu'on purge \c contacts avant d'y mettre les informations lues afin de |
|
964 simplifier le processus de lecture de fichier. Une façon plus avancée de |
|
965 procéder serait de lire les contacts dans un objet QMap temporaire, et |
|
966 de copier uniquement les contacts n'existant pas encore dans |
|
967 \c contacts. |
|
968 |
|
969 \snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part3 |
|
970 |
|
971 Pour afficher les contacts lus depuis le fichier, on doit d'abord |
|
972 valider les données obtenues afin de s'assurer que le fichier lu |
|
973 contient effectivement des entrées de carnet d'adresses. Si c'est le |
|
974 cas, on affiche le premier contact; sinon on informe l'utilisateur du |
|
975 problème par une QMessageBox. Enfin, on met à jour l'interface afin |
|
976 d'activer et de désactiver les boutons de façon appropriée. |
|
977 */ |
|
978 |
|
979 /*! |
|
980 \page tutorials-addressbook-fr-part7.html |
|
981 \previouspage {tutorials/addressbook-fr/part6}{Chapitre 6} |
|
982 \contentspage {Tutoriel "Carnet d'adresses"}{Sommaire} |
|
983 \example tutorials/addressbook-fr/part7 |
|
984 \title Carnet d'adresse 7 - Fonctionnalités avancées |
|
985 |
|
986 Ce chapitre couvre quelques fonctionnalités additionnelles qui |
|
987 feront de notre carnet d'adresses une application plus pratique |
|
988 pour une utilisation quotidienne. |
|
989 |
|
990 \image addressbook-tutorial-part7-screenshot.png |
|
991 |
|
992 Bien que notre application carnet d'adresses soit utile en tant que telle, |
|
993 il serait pratique de pouvoir échanger les contacts avec d'autres applications. |
|
994 Le format vCard est un un format de fichier populaire pour échanger |
|
995 ce type de données. |
|
996 Dans ce chapitre, nous étendrons notre carnet d'adresses pour permettre |
|
997 d'exporter des contacts dans des fichiers vCard \c{.vcf}. |
|
998 |
|
999 \section1 Définition de la classe AddressBook |
|
1000 |
|
1001 Nous ajoutons un objet QPushButton, \c exportButton, et un slot |
|
1002 public correspondant, \c exportAsVCard(), à notre classe \c AddressBook |
|
1003 dans le fichier \c addressbook.h. |
|
1004 |
|
1005 \snippet tutorials/addressbook/part7/addressbook.h exportAsVCard() declaration |
|
1006 \dots |
|
1007 \snippet tutorials/addressbook/part7/addressbook.h exportButton declaration |
|
1008 |
|
1009 \section1 Implémentation de la classe AddressBook |
|
1010 |
|
1011 Dans le constructeur de \c AddressBook, nous connectons le signal |
|
1012 \l{QPushButton::clicked()}{clicked()} de \c{exportButton} au slot |
|
1013 \c exportAsVCard(). |
|
1014 Nous ajoutons aussi ce bouton à \c buttonLayout1, le layout responsable |
|
1015 du groupe de boutons sur la droite. |
|
1016 |
|
1017 Dans la méthode \c exportAsVCard(), nous commençons par extraire le |
|
1018 nom du contact dans \n name. Nous déclarons \c firstname, \c lastName et |
|
1019 \c nameList. |
|
1020 Ensuite, nous cherchons la position du premier espace blanc de \c name. |
|
1021 Si il y a un espace, nous séparons le nom du contact en \c firstName et |
|
1022 \c lastName. Finalement, nous remplaçons l'espace par un underscore ("_"). |
|
1023 Si il n'y a pas d'espace, nous supposons que le contact ne comprend que |
|
1024 le prénom. |
|
1025 |
|
1026 \snippet tutorials/addressbook/part7/addressbook.cpp export function part1 |
|
1027 |
|
1028 Comme pour la méthode \c saveToFile(), nous ouvrons une boîte de dialogue |
|
1029 pour donner la possibilité à l'utilisateur de choisir un emplacement pour |
|
1030 le fichier. Avec le nom de fichier choisi, nous créons une instance de QFile |
|
1031 pour y écrire. |
|
1032 |
|
1033 Nous essayons d'ouvrir le fichier en mode \l{QIODevice::}{WriteOnly}. Si |
|
1034 cela échoue, nous affichons un QMessageBox pour informer l'utilisateur |
|
1035 à propos de l'origine du problème et nous quittons la méthode. Sinon, nous passons le |
|
1036 fichier comme paramètre pour créer un objet QTextStream, \c out. De la même façon que |
|
1037 QDataStream, la classe QTextStream fournit les fonctionnalités pour |
|
1038 lire et écrire des fichiers de texte. Grâce à celà, le fichier \c{.vcf} |
|
1039 généré pourra être ouvert et édité à l'aide d'un simple éditeur de texte. |
|
1040 |
|
1041 \snippet tutorials/addressbook/part7/addressbook.cpp export function part2 |
|
1042 |
|
1043 Nous écrivons ensuite un fichier vCard avec la balise \c{BEGIN:VCARD}, |
|
1044 suivit par \c{VERSION:2.1}. |
|
1045 Le nom d'un contact est écrit à l'aide de la balise \c{N:}. Pour la balise |
|
1046 \c{FN:}, qui remplit le titre du contact, nous devons vérifier si le contact |
|
1047 à un nom de famille défini ou non. Si oui, nous utilions les détails de |
|
1048 \c nameList pour remplir le champ, dans le cas contraire on écrit uniquement le contenu |
|
1049 de \c firstName. |
|
1050 |
|
1051 \snippet tutorials/addressbook/part7/addressbook.cpp export function part3 |
|
1052 |
|
1053 Nous continuons en écrivant l'adresse du contact. Les points-virgules |
|
1054 dans l'adresse sont échappés à l'aide de "\\", les retours de ligne sont |
|
1055 remplacés par des points-virgules, et les vigules sont remplacées par des espaces. |
|
1056 Finalement nous écrivons les balises \c{ADR;HOME:;} suivies par l'adresse |
|
1057 et la balise \c{END:VCARD}. |
|
1058 |
|
1059 \snippet tutorials/addressbook/part7/addressbook.cpp export function part4 |
|
1060 |
|
1061 À la fin de la méthode, un QMessageBox est affiché pour informer l'utilisateur |
|
1062 que la vCard a été exportée avec succès. |
|
1063 |
|
1064 \e{vCard est une marque déposée de \l{http://www.imc.org} |
|
1065 {Internet Mail Consortium}}. |
|
1066 */ |