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