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
|
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Free Documentation License
**
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of this
** file.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/
/*!
\page tutorials-addressbook-sdk.html
\startpage {index.html}{Qt Reference Documentation}
\nextpage {examples/addressbook-sdk/part1}{Chapter 1}
\title Address Book Tutorial
\brief An introduction to GUI programming with Qt and Qt Creator,
describing in detail how to put together a simple yet fully-
functioning application.
This tutorial gives an introduction to GUI programming using the Qt SDK.
\image addressbook-tutorial-screenshot.png
In the process, you will learn about some basic technologies provided by
Qt, such as:
\list
\o Widgets and layout managers
\o Container classes
\o Signals and slots
\o Input and output devices
\endlist
All these technologies will be introduced via the Qt Creator Integrated
Development Environment (IDE).
If you are completely new to Qt, please read \l{How to Learn Qt} if you
have not already done so.
The tutorial's source code is located in Qt's
\c{examples/tutorials/addressbook} directory.
Tutorial chapters:
\list 1
\o \l{examples/addressbook-sdk/part1}{Designing the User Interface}
\o \l{examples/addressbook-sdk/part2}{Adding Addresses}
\o \l{examples/addressbook-sdk/part3}{Navigating between Entries}
\o \l{examples/addressbook-sdk/part4}{Editing and Removing Addresses}
\o \l{examples/addressbook-sdk/part5}{Adding a Find Function}
\o \l{examples/addressbook-sdk/part6}{Loading and Saving}
\o \l{examples/addressbook-sdk/part7}{Additional Features}
\endlist
Although this little application does not look much like a fully-fledged
modern GUI application, it uses many of the basic techniques that are used
in more complex applications. After you have worked through it, we
recommend checking out the \l{mainwindows/application}{Application}
example, which presents a small GUI application, with menus, toolbars, a
status bar, and so on.
*/
/*!
\page tutorials-addressbook-sdk-part1.html
\contentspage {Address Book Tutorial}{Contents}
\nextpage {examples/addressbook-sdk/part2}{Chapter 2}
\example examples/addressbook-sdk/part1
\title Address Book 1 - Designing the User Interface
The first part of this tutorial covers the design of the basic graphical
user interface (GUI) you use for the Address Book application.
The first step to creating a GUI program is to design the user interface.
In this chapter, your goal is to set up the labels and input fields needed
to implement a basic address book application. The figure below is a
screenshot of our expected output.
\image addressbook-tutorial-part1-screenshot.png
Begin by launching Qt Creator and use it to generate a new project. To
do this, select \gui{File} > \gui{New File or Project...} >
\gui{Qt Application Project} > \gui{Qt Gui Application} and
click \gui OK. Set your project name to \bold part1 with the QtCore and
QtGui modules checked. Ensure that you select QWidget as your base class
and name it \c AddressBook.
When you click \gui Next, \e five files will be generated in this
\gui{Project}:
\list
\o \c{main.cpp} - the file containing a \c main() function, with an
instance of \c AddressBook,
\o \c{addressbook.cpp} - the implementation file for the
\c AddressBook class,
\o \c{addressbook.h} - the definition file for the \c AddressBook
class,
\o \c{addressbook.ui} - the user interface file created with \QD,
and
\o \c{part1.pro} - the project file.
\endlist
Now that you have all the files you need, click \gui Finish so you can
start designing the user interface.
\note For more details on how to create a \gui Project with Qt Creator,
refer to \l{Creating a Project}.
\section1 Placing Widgets on The Form
\image addressbook-tutorial-part1-creator-screenshot.png
In the \gui{Projects} sidebar, double-click on the \c{addressbook.ui} file.
The \QD plugin will be launched, allowing you to design your program's user
interface.
\image addressbook-tutorial-part1-designer-screenshot.png
You require two \l{QLabel}s to label the input fields as well as a
QLineEdit and a QTextEdit for the input fields. To create this follow the
steps mentioned below:
\list
\o Drag those widgets from the \gui{Widget Box} to your form.
\o In the \gui{Property Editor}, set their \gui{objectName} property to
\c nameLabel and \c addressLabel for the \l{QLabel}s, \c nameLine
for the QLineEdit and finally, \c addressText for the QTextEdit.
\o Position the widgets properly, according to the screenshot above.
\o Use a QGridLayout to position our labels and input fields in a
structured manner. QGridLayout divides the available space into
a grid and places widgets in the cells you specify with row and
column numbers.
\o Place the caption of the \c addressLabel on the top, change the
vertical alignment property to \c AlignTop.
\endlist
The figure below shows the layout cells and the position of our widgets.
Place your widgets accordingly and save the form by choosing
\gui{File} > \gui{Save} or use the shortcut key \key{Ctrl+S}.
\image addressbook-tutorial-part1-labeled-screenshot.png
A common mistake when designing user interfaces with \QD is overlooking the
top level widget's layout. Unlike sub-layouts, which \QD displays with a
red border, top level layouts have no graphical representation. Layouts are
necessary for top level widgets, in this case QWidget, to ensure that when
the window is resized, the widgets on the form will resize accordingly. You
can try this out by pressing \key{Alt+Shift+R} now. To correct it, click
anywhere on the form and select \gui{Lay out Horizontally} or
\gui{Lay out Vertically}. The output will be the same. Now your widgets
will resize correctly.
\note Refer to the \l{Layout Classes} document for more
details on Qt's layout management classes. In addition, the
\l{Getting to Know Qt Designer} document explains how to use
layouts with \QD.
\section1 The AddressBook Class
The \l{examples/addressbook-sdk/part1/addressbook.h}{\c addressbook.h} file
is used to define the \c AddressBook class.
Let's take a look at what is already provided for us by Qt Creator. The
\c AddressBook class has been defined as a QWidget subclass with a
constructor and destructor.The Q_OBJECT macro is used to indicate that this
class uses internationalization as well as Qt's signals and slots features.
Although the macro implements some of Qt's more advanced features, for now,
it is useful to think of it as a shortcut that allows us to use the
\l{QObject::}{tr()} and \l{QObject::}{connect()} functions.
\snippet examples/addressbook-sdk/part1/addressbook.h class definition
Qt Creator's \gui{Project Wizard} provides you with the \c Ui object as a
way to access the widgets on our form.
The \l{examples/addressbook-sdk/part1/addressbook.cpp}{\c addressbook.cpp}
file is used to implement the \c AddressBook class. The constructor sets up
the \c ui file; the destructor deletes it.
\snippet examples/addressbook-sdk/part1/addressbook.cpp class implementation
\section1 The \c{main()} Function
The \l{examples/addressbook-sdk/part1/main.cpp}{\c main.cpp} file contains
the \c{main()} function It is generated by the \gui{Project Wizard}.
Within this function, a QApplication object, \c a, is instantiated.
QApplication is responsible for various application-wide resources, such as
the default font and cursor, and for running an event loop. Hence, there is
always one QApplication object in every GUI application using Qt.
\snippet examples/addressbook-sdk/part1/main.cpp main function
The code constructs a new \c AddressBook widget on the stack and
invokes its \l{QWidget::}{show()} function to display it.
However, the widget will not be shown until the application's event
loop is started. This is done by calling the application's
\l{QApplication::}{exec()} function. Finally, the result returned by
\l{QApplication::}{exec()} is used as the \c main() function's return
value.
\section1 Running the Application
To run your application with Qt Creator, simply click,
\inlineimage qtcreator-run.png.
A bare bones Address Book will be displayed.
\section1 Qt Programming - Subclassing
When writing Qt programs, you usually subclass Qt objects to add
functionality. This is one of the essential concepts behind creating custom
widgets or collections of standard widgets. Subclassing to extend or change
the behavior of a widget has the following advantages:
\list
\o You can write implementations of virtual or pure virtual functions
to obtain exactly what you need, falling back on the base class's
implementation when necessary.
\o It allows you to encapsulate parts of the user interface within a
class, so that the other parts of the application do not need to
know about the individual widgets in the user interface.
\o The subclass can be used to create multiple custom widgets in the
same application or library, and the code for the subclass can be
reused in other projects.
\endlist
Since Qt does not provided a specific address book widget, you subclass a
standard Qt widget class and add features to it. The \c AddressBook class
you create in this tutorial can be reused in situations where a basic
address book is needed.
*/
/*!
\page tutorials-addressbook-sdk-part2.html
\previouspage Address Book 1 - Designing the User Interface
\contentspage {Address Book Tutorial}{Contents}
\nextpage {examples/addressbook-sdk/part3}{Chapter 3}
\example examples/addressbook-sdk/part2
\title Address Book 2 - Adding Addresses
The next step to creating our basic address book application is to allow a
little bit of user interaction.
\image addressbook-tutorial-part2-add-contact.png
You will provide a push button that the user can click to add a new
contact. Also, some form of data structure is needed to store these
contacts in an organized way.
\section1 Placing Widgets on The Form
You can continue with the form from the last chapter; you have the
labels and input fields set up, but you need to add push buttons to
complete the process of adding a contact. Break the existing layouts by
following the steps below:
\list
\o Select, \gui{Break Layout} from the context menu. You might have to
do a \gui{Select All} with \key{Ctrl+A} first..
\o Add three push buttons and double-click on each of them to set
their text to "Add", "Submit", and "Cancel".
\o Set the \c objectName of the buttons to \c addButton,
\c submitButton and \c cancelButton respectively.
\o A \gui{Vertical Spacer} is required to ensure that the push buttons
will be laid out neatly; drag one from the \gui{Widget Box}.
\o Lay out these three push buttons and the spacer vertically, by
selecting all three of them using \key{Ctrl + click} and selecting
\gui{Lay out Vertically} from the context menu. Alternatively you
can use the \key{Ctrl+L} shortcut key.
\note Use the spacer as you do not want the buttons to be evenly
spaced, but arranged closer to the top of the widget.
\o The figure below shows the difference between using the spacer and
not using it.
\image addressbook-tutorial-part2-stretch-effects.png
\o Select all the objects on the form using, \key{Ctrl+A} and lay them
out in a grid.
\o Lastly, set the top level widget's layout by right-clicking anywhere
on the widget and selecting \gui{Lay out Horizontally} or
\gui{Lay out Vertically}.
\endlist
The final design of the form is shown in the screenshot below:
\image addressbook-tutorial-part2-form-design.png
\section1 The AddressBook Class
To ensure that the Address Book reacts to user interaction, you need to
write slots for each push button that you added earlier. A slot is a
function that responds to a particular signal. This concept will be
discussed further in detail below. However, for an overview of Qt's signals
and slots concept, you can refer to the \l{Signals and Slots} document.
In the \l{examples/addressbook-sdk/part2/addressbook.h}{\c addressbook.h}
file, add the following code:
\snippet examples/addressbook-sdk/part2/addressbook.h slot definition
Since the \c AddressBook class is a subclass of QWidget, Qt Creator
includes QWidget in the header file.
\snippet examples/addressbook-sdk/part2/addressbook.h include
You need a container to store our address book contacts, so that you can
traverse and display them. A QMap object, \c contacts, is used for this
purpose as it holds a key-value pair: the contact's name as the \e key, and
the contact's address as the \e value.
\snippet examples/addressbook-sdk/part2/addressbook.h members
You also declare two private QString objects, \c oldName and \c oldAddress.
These objects are needed to hold the name and address of the contact that
was last displayed, before you click \gui Add. So, when you
click \gui Cancel, you can revert to displaying the details of the last
contact.
Let's move on to implementing the slots defined earlier. Within the
constructor of \c AddressBook, you set up our fields by ensuring that
\c nameLine and \c addressText are read-only, so that you can only display
but not edit existing contact details.
\note In order to prevent crashes, you need make sure that the
autogenerated \c setupUi() call is always first in the constructor.
\snippet examples/addressbook-sdk/part2/addressbook.cpp setup fields
You also hide both \c submitButton and \c cancelButton as they will only be
displayed when you click \gui Add, and this is handled by the
\c addContact() function discussed below.
\snippet examples/addressbook-sdk/part2/addressbook.cpp signal slot
You connect the push buttons' \l{QAbstractButton::}{clicked()} signal to
their respective slots. The figure below illustrates this.
\image addressbook-tutorial-part2-signals-and-slots.png
Finally, set the window title to "Simple Address Book" using the
\l{QWidget::}{setWindowTitle()} function. The tr() method allows us
to translate user interface strings.
\snippet examples/addressbook-sdk/part2/addressbook.cpp window title
\section2 The \c addContact() Function
In this function, begin by storing the last displayed contact details
in \c oldName and \c oldAddress. Then clear these input fields and turn
off the read-only mode. The focus is set on \c nameLine and display
\c submitButton and \c cancelButton; but disable \c addButton.
\snippet examples/addressbook-sdk/part2/addressbook.cpp addContact
\section2 The \c submitContact() Function
This function can be divided into three parts:
\list 1
\o Extract the contact's detail from \c nameLine and \c addressText
and store them in QString objects. Also validate to ensure that
you did not click \gui Submit with empty input fields;
otherwise, a QMessageBox is displayed to remind you for a name
and address.
\snippet examples/addressbook-sdk/part2/addressbook.cpp submitContact part1
\o Then proceed to check if the contact already exists. If it does
not exist, add the contact to \c contacts and display a
QMessageBox to inform you about this, preventing you from
adding duplicate contacts. Our \c contacts object is based on
key-value pairs or name and address, hence, you want to ensure that
\e key is unique.
\snippet examples/addressbook-sdk/part2/addressbook.cpp submitContact part2
\o Once you have handled both cases mentioned above, restore the
push buttons to their normal state with the following code:
\snippet examples/addressbook-sdk/part2/addressbook.cpp submitContact part3
\endlist
The screenshot below shows the QMessageBox object used to display
information messages to the user.
\image addressbook-tutorial-part2-add-successful.png
\section2 The \c cancel() Function
This function restores the last displayed contact details and enables
\c addButton, as well as hides \c submitButton and \c cancelButton.
\snippet examples/addressbook-sdk/part2/addressbook.cpp cancel
The general idea behind adding a contact is to give you the
flexibility to click \gui Submit or \gui Cancel at any time. The flowchart
below further explains this concept:
\image addressbook-tutorial-part2-add-flowchart.png
\section1 Running the Application
Run your application now. You will be able to add as many unique contacts
as you like.
*/
/*!
\page tutorials-addressbook-sdk-part3.html
\previouspage Address Book 2 - Adding Addresses
\contentspage {Address Book Tutorial}{Contents}
\nextpage {examples/addressbook-sdk/part4}{Chapter 4}
\example examples/addressbook-sdk/part3
\title Address Book 3 - Navigating between Entries
The address book application is now half complete. You need to add some
functions to navigate between contacts. But first, you have to decide what
sort of a data structure you would like to use to hold these contacts.
In Chapter 2, you used a QMap of key-value pairs with the contact's name as
the \e key, and the contact's address as the \e value. This works well for
your case. However, in order to navigate and display each entry, a little
bit of enhancement is needed.
Enhance the QMap by making it replicate a data structure similar to a
circularly-linked list, where all elements are connected, including the
first element and the last element. The figure below illustrates this data
structure.
\image addressbook-tutorial-part3-linkedlist.png
\section1 Placing Widgets on The Form
So far, your application allows us to add new contacts. However, you also
need to traverse the existing contacts. To do so follow the steps
mentioned below:
\list
\o Add two push buttons at the bottom of your application and name
them: \gui Next and \gui Previous.
\o The buttons' \c objectName should be \c nextButton and
\c previousButton, respectively.
\o Break your top level layout by right-clicking on \c AddressBook in
the \gui{Object Inspector} and then select \gui{Lay out|Break Layout}.
\o Place the \gui Next and \gui Previous buttons in a horizontal
layout.
\o Drag and drop the buttons together with their layout into the
existing grid layout.
\o Set a top level layout for the widget again.
\endlist
The screenshot below illustrates what you will see as the button layout
approaches the grid layout; drop it then.
\image addressbook-tutorial-part3-drop-in-gridlayout.png
\note Follow basic conventions for \c next() and \c previous() functions
by placing the \c nextButton on the right and the \c previousButton on the
left.
\section1 The AddressBook Class
In order to add navigation functions to the address book application,
you need to add two more slots to our \c AddressBook class: \c next() and
\c previous().
\snippet examples/addressbook-sdk/part3/addressbook.h slot definition
In the \c AddressBook constructor, you setup your fields and disable them
by default. This is because navigation is only enabled when there is more
than one contact in the address book.
\snippet examples/addressbook-sdk/part3/addressbook.cpp setup fields
Next, connect the buttons to their respective slots:
\snippet examples/addressbook-sdk/part3/addressbook.cpp signal slot
The screenshot below is your expected graphical user interface. Notice that
it is getting closer to your final application.
\image addressbook-tutorial-part3-screenshot.png
Within your \c addContact() function, you have to disable the \gui Next and
\gui Previous buttons so that you do not attempt to navigate while
adding a contact.
\snippet examples/addressbook-sdk/part3/addressbook.cpp disable navigation
Also, in your \c submitContact() function, enable the navigation buttons,
depending on the size of \c contacts. As mentioned earlier, navigation is
only enabled when there is more than one contact in the address book. The
following lines of code demonstrates how to do this:
\snippet examples/addressbook-sdk/part3/addressbook.cpp enable navigation
Also include these lines of code in the \c cancel() function.
Recall that you intend to emulate a circularly-linked list with your QMap
object, \c contacts. So in the \c next() function, obtain an iterator
for \c contacts and then:
\list
\o If the iterator is not at the end of \c contacts, increment it by
one.
\o If the iterator is at the end of \c contacts, move it to the
beginning of \c contacts. This gives an illusion that our QMap
is working like a circularly-linked list.
\endlist
\snippet examples/addressbook-sdk/part3/addressbook.cpp next
Once you have iterated to the current object in \c contacts, display its
contents on \c nameLine and \c addressText.
Similarly, for the \c previous() function, obtain an iterator for
\c contacts and then:
\list
\o If the iterator is at the end of \c contacts, clear the display
and return.
\o If the iterator is at the beginning of \c contacts, move it to
the end.
\o Then decrement the iterator by one.
\endlist
\snippet examples/addressbook-sdk/part3/addressbook.cpp previous
Again, display the contents of the current object in \c contacts.
*/
/*!
\page tutorials-addressbook-sdk-part4.html
\previouspage Address Book 3 - Navigating between Entries
\contentspage {Address Book Tutorial}{Contents}
\nextpage {examples/addressbook-sdk/part5}{Chapter 5}
\example examples/addressbook-sdk/part4
\title Address Book 4 - Editing and Removing Addresses
This chapter looks at ways to modify the contents of contacts stored
in the address book application.
\image addressbook-tutorial-part4-screenshot.png
You now have an address book that not only holds contacts in an organized
manner, but also allows navigation. It would be convenient to include edit
and remove functions so that a contact's details can be changed when
needed. However, this requires a little improvement, in the form of enums.
In our previous chapters, you had two modes: \c AddingMode and
\c NavigationMode - but they were not defined as enums. Instead, you
enabled and disabled the corresponding buttons manually, resulting in
multiple lines of repeated code.
In this chapter, define the \c Mode enum with three different values:
\list
\o \c{NavigationMode}
\o \c{AddingMode}
\o \c{EditingMode}
\endlist
\section1 Placing Widgets on The Form
To edit and remove contacts, you need two push buttons. Drag them and name
them accordingly. Their \c objectName properties should be \c editButton
and \c removeButton, respectively. The quickest way to place these two
buttons into our existing layout, is to simply drag and drop them. Use the
screenshot below as a guide:
\image addressbook-tutorial-part4-drop-in-gridlayout.png
\section1 The AddressBook Class
Update the header file to contain the \c Mode enum:
\snippet examples/addressbook-sdk/part4/addressbook.h enum
Also add two new slots, \c editContact() and \c removeContact(), to your
current list of public slots.
\snippet examples/addressbook-sdk/part4/addressbook.h slot definition
In order to switch between modes, introduce the \c updateInterface()
function to control the enabling and disabling of all push buttons.
\snippet examples/addressbook-sdk/part4/addressbook.h updateInterface
Lastly, declare \c currentMode to keep track of the enum's current mode.
\snippet examples/addressbook-sdk/part4/addressbook.h current mode
Let's begin by implementing the mode-changing features of the address book
application. The \c editButton and \c removeButton are disabled by default,
as the address book starts up with zero contacts in memory.
\snippet examples/addressbook-sdk/part4/addressbook.cpp extract objects
These buttons are then connected to their respective slots,
\c editContact() and \c removeContact.
\snippet examples/addressbook-sdk/part4/addressbook.cpp signal slot
Now look at the \c editContact() and \c removeContact() functions in
detail.
\section2 The \c editContact() Function
This function stores the contact's old details in \c oldName and
\c oldAddress, before switching the mode to \c EditingMode. In this mode,
the \c submitButton and \c cancelButton are both enabled. Hence, the user
can change the contact's details and click either button.
\snippet examples/addressbook-sdk/part4/addressbook.cpp editContact
Since you will reuse the \c submitButton for both: adding a new contact and
editing an existing contact, you need to modify our existing
\c submitContact() function. So, divide it in two with an \c{if-else}
statement.
First, check \c currentMode to see if it is in \c AddingMode. If it is,
proceed with your adding process.
\snippet examples/addressbook-sdk/part4/addressbook.cpp submitContact part1
\dots
\snippet examples/addressbook-sdk/part4/addressbook.cpp submitContact part2
Otherwise, check to see if \c currentMode is in \c EditingMode. If it
is, compare \c oldName with \c name. If the name has changed, remove
the old contact from \c contacts and insert the newly updated contact.
\snippet examples/addressbook-sdk/part4/addressbook.cpp submitContact part3
If only the contact's address has changed, that is the \c oldAddress is
not the same as \c address, update the contact's address. Lastly, set
\c currentMode to \c NavigationMode. This is an important step as it
re-enables all the disabled push buttons.
To remove a contact from the address book, implement the
\c removeContact() function.
\snippet examples/addressbook-sdk/part4/addressbook.cpp removeContact
This function first checks to see if the contact exists in \c contacts. If
it does, display a QMessageBox, to confirm the removal with the user.
Once the user has confirmed, call \c previous() to ensure that the
user interface shows another contact, and remove the contact using
\l{QMap}'s \l{QMap::}{remove()} function. As a courtesy, display a
QMessageBox to inform the user. Both the message boxes used in this
function are shown below:
\image addressbook-tutorial-part4-confirm.png
\image addressbook-tutorial-part4-remove.png
\section2 The \c updateInterface() Function
This function is mentioned earlier as a means to enable and disable the
push buttons, depending on the current mode. The function updates the
current mode according to the \c mode argument passed to it, assigning it
to \c currentMode, before checking its value.
Each of the push buttons is then enabled or disabled, depending on the
current mode. The code for \c AddingMode and \c EditingMode is shown below:
\snippet examples/addressbook-sdk/part4/addressbook.cpp updateInterface part1
For \c NavigationMode, however, include conditions within the parameters
of the QPushButton::setEnabled() function. This is to ensure that
\c editButton and \c removeButton are enabled when there is at least one
contact in the address book; \c nextButton and \c previousButton are only
enabled when there is more than one contact in the address book.
\snippet examples/addressbook-sdk/part4/addressbook.cpp updateInterface part2
By performing the task of setting the mode and updating the user interface
in the same function, you avoid the possibility of the user interface
getting "out of sync" with the internal state of the application.
To maintain consistency, you need to modify our \c addContact() and
\c cancel() functions respectively. Below is the code:
\snippet examples/addressbook-sdk/part4/addressbook.cpp addContact
\dots
\snippet examples/addressbook-sdk/part4/addressbook.cpp cancel
*/
/*!
\page tutorials-addressbook-sdk-part5.html
\previouspage Address Book 4 - Editing and Removing Addresses
\contentspage {Address Book Tutorial}{Contents}
\nextpage {examples/addressbook-sdk/part6}{Chapter 6}
\example examples/addressbook-sdk/part5
\title Address Book 5 - Adding a Find Function
This chapter looks at ways to locate contacts and addresses in the
address book application.
\image addressbook-tutorial-part5-screenshot.png
As you keep adding contacts to your address book, it becomes tedious to
navigate them with the \gui Next and \gui Previous buttons. In this case,
a \gui Find function would be more efficient in looking up contacts. The
screenshot above shows the \gui Find button and its position on the panel
of buttons.
When you click on the \gui Find button, it is useful to display a
dialog prompting the user for a contact's name. Qt provides QDialog, which
you subclass in this chapter, to implement a FindDialog class.
\section1 Designing The FindDialog
\image addressbook-tutorial-part5-finddialog-in-designer.png
Begin by adding a new \c{.ui} file and a corresponding class to our
project. Right click on your project and select
\gui{Add New...} > \gui{Qt} > \gui{Qt Designer Form Class}.
In the \gui{Qt Designer Form Class} dialog, select
\e{Dialog without buttons}. Name the class \c{FindDialog} and add the files
it to your project. Open your new form in the \QD form editor within
Qt Creator by double-clicking on the \c{finddialog.ui} file in
the \gui{Project Sidebar}.
To replicate the screenshot above, you need a label, a line edit, and a push
button. Drag these onto your form. Set their text accordingly and name them
\c label, \c lineEdit, and \c findButton, respectively. Place these widgets
in a horizontal layout. Then set a top level layout - either horizontal or
vertical.
\section1 Implementing The FindDialog Class
Let's look at \c{FindDialog}'s header file. Define a public function,
\c findText(), to be used by classes that instantiate \c FindDialog. This
function allows the classes to obtain the search string entered by
you. A public slot, \c findClicked(), is also defined to handle the
search string when you click the \gui Find button.
\snippet examples/addressbook-sdk/part5/finddialog.h findText
\dots
\snippet examples/addressbook-sdk/part5/finddialog.h findClicked
Now, lets look at our constructor in the \c{finddialog.cpp} file.
\snippet examples/addressbook-sdk/part5/finddialog.cpp constructor
In \c findClicked(), validate to ensure that you did not click the
\gui Find button without entering a contact's name. Then, set
\c findText to the search string, extracted from \c lineEdit. After that,
clear the contents of \c lineEdit and hide the dialog.
\snippet examples/addressbook-sdk/part5/finddialog.cpp findClicked
\c findText() is public, which makes it easy for classes instantiating
and using \c FindDialog to access the search string that you have entered
and accepted.
\snippet examples/addressbook-sdk/part5/finddialog.cpp findText
Finally, connect your signals to their respective slots. Notice that
\c{findButton}'s \l{QPushButton::}{clicked()} signal is connected to
\c findClicked(), which calls \l{QDialog::}{accept()} or
\l{QDialog::}{reject()}. The \l{QDialog::}{accept()} slot provided by
QDialog hides the dialog and sets the result code to
\l{QDialog::}{Accepted}, while \l{QDialog::}{reject()}
sets it to \l{QDialog::}{Rejected} accordingly. Use this function to help
\c{AddressBook}'s \c findContact() function know when the \c FindDialog
object has been closed. This logic will be explained in further detail
when discussing the \c findContact() function.
\image addressbook-tutorial-part5-signals-and-slots.png
\section1 The AddressBook Class
To ensure that you can use \c FindDialog from within your \c AddressBook
class, include \c finddialog.h in the \c addressbook.h file.
\snippet examples/addressbook-sdk/part5/addressbook.h include
So far, all your address book features have a QPushButton and a
corresponding slot. Similarly, the \gui Find feature, has
\c{ui->findButton} and \c findContact().
\snippet examples/addressbook-sdk/part5/addressbook.h slot definition
Once you have instantiated a dialog, you might want to use it more than
once; using a private variable allows you to refer to it from more than one
place in the class.
Within the \c AddressBook class's constructor, connect the
\c{findButton}'s \l{QPushButton::}{clicked()} signal to \c findContact().
\snippet examples/addressbook-sdk/part5/addressbook.cpp signal slot
Now, all that is left is the code for our \c findContact() function:
\snippet examples/addressbook-sdk/part5/addressbook.cpp findContact
Start out by displaying the \c FindDialog instance, \c dialog. This is
when you enter a contact name to look up. Once you click the
dialog's \c findButton, the dialog is hidden and the result code is set to
either QDialog::Accepted or QDialog::Rejected by the FindDialog's
\c findClicked() method. This ensures that you only search for a contact
if you have typed something in the FindDialog's line edit.
Then proceed to extract the search string, which in this case is
\c contactName, using \c{FindDialog}'s \c findText() function. If the
contact exists in our address book, display it immediately. Otherwise,
display the QMessageBox shown below to indicate that their search
failed.
\image addressbook-tutorial-part5-dialogbox.png
The concept behind finding a contact only applies for cases where you have
more than two contacts in our address book. Hence, implement this
behavior by modifying our \c{Navigation Mode} within your
\c updateInterface() function, by only enabling the \gui Find button when
you have more than two contacts.
\snippet examples/addressbook-sdk/part5/addressbook.cpp enable
*/
/*!
\page tutorials-addressbook-sdk-part6.html
\previouspage Address Book 5 - Adding a Find Function
\contentspage {Address Book Tutorial}{Contents}
\nextpage {examples/addressbook-sdk/part7}{Chapter 7}
\example examples/addressbook-sdk/part6
\title Address Book 6 - Loading and Saving
This chapter covers the file handling features of Qt that is used to write
loading and saving routines for the address book application.
\image addressbook-tutorial-part6-screenshot.png
Although browsing and searching for contacts are useful features, your
address book is not really ready for use until you can save existing
contacts and load them again at a later time. Qt provides a number of
classes for \l{Input/Output and Networking}{input and output}, but you have
chosen to use two which are simple to use in combination: QFile and
QDataStream.
A QFile object represents a file on disk that can be read from and written
to. QFile is a subclass of the more general QIODevice class which represents
many different kinds of devices.
A QDataStream object is used to serialize binary data so that it can be
stored in a QIODevice and retrieved again later. Reading from a QIODevice
and writing to it is as simple as opening the stream - with the respective
device as a parameter - and reading from or writing to it.
\section1 Placing Widgets on The Form
To load and save files containing contact details, you need two push
buttons. Drag them and name them accordingly. Their \c objectName
properties should be \c loadButton and \c saveButton, respectively. Then,
similar to \l{Address Book 5 - Adding a Find Function}{Chapter 5}, place
these buttons in our layout simply by dragging and dropping them.
The \c text property of our push buttons are \gui{Load...} and
\gui{Save...} respectively. Ideally, it would be more user-friendly to set
the push buttons' labels to \gui{Load contacts from file} and
\gui{Save contacts to file}. However, due to the size of our push buttons,
set the labels to \gui{Load...} and \gui{Save...} instead.
Fortunately, Qt Creator's \QD plugin provides a simple way to set tooltips
with the \c toolTip property. So, set your buttons' tooltips to
\gui{Load contacts from file} and \gui{Save contacts to file} respectively.
To test your tooltip, use \key{Alt+Shift+R} and hover your mouse cursor on
the push buttons.
\image addressbook-tutorial-part6-propertyeditor.png
\section1 The AddressBook Class
Declare two public slots, \c saveToFile() and \c loadFromFile().
\snippet examples/addressbook-sdk/part6/addressbook.h slot definition
Now lets look at the \c saveToFile() and \c loadFromFile() functions in
detail.
\section2 The \c saveToFile() Function
To save a contact, first obtain \c fileName using
QFileDialog::getSaveFileName(). This is a convenience function provided by
QFileDialog, which pops up a modal file dialog and allows you to enter
a file name or select any existing \c{.abk} file. The \c{.abk} file is our
Address Book extension that you create when you save contacts.
\snippet examples/addressbook-sdk/part6/addressbook.cpp saveToFile part1
The file dialog that pops up is displayed in the screenshot below:
\image addressbook-tutorial-part6-savedialog.png
If \c fileName is not empty, create a QFile object, \c file, with
\c fileName. The QFile object works with QDataStream as QFile is a
QIODevice.
Next, attempt to open the file in \l{QIODevice::}{WriteOnly} mode. If
this is unsuccessful, display a QMessageBox to inform the user.
\snippet examples/addressbook-sdk/part6/addressbook.cpp saveToFile part2
Otherwise, instantiate a QDataStream object, \c out, to write the open
file. QDataStream requires that the same version of the stream is used for
reading and writing. Ensure that this is the case by setting the version
used to the version introduced with Qt 4.5 before serializing the data into
\c file.
\snippet examples/addressbook-sdk/part6/addressbook.cpp saveToFile part3
\section2 The \c loadFromFile() Function
To load a contact, also obtain \c fileName using
QFileDialog::getOpenFileName(). This function, the counterpart to
QFileDialog::getSaveFileName(), also pops up the modal file dialog and
allows you to enter a file name or select any existing \c{.abk} file
to load it into the address book.
\snippet examples/addressbook-sdk/part6/addressbook.cpp loadFromFile part1
On Windows, for example, this function pops up a native file dialog, as
shown in the following screenshot.
\image addressbook-tutorial-part6-opendialog.png
If \c fileName is not empty, again, use a QFile object, \c file, and
attempt to open it in \l{QIODevice::}{ReadOnly} mode. Similar to your
implementation of \c saveToFile(), if this attempt is unsuccessful,
display a QMessageBox to inform the user.
\snippet examples/addressbook-sdk/part6/addressbook.cpp loadFromFile part2
Otherwise, instantiate a QDataStream object, \c in, set its version as
above and read the serialized data into hte \c contacts data structure. The
\c contacts object is emptied before data is read into it to simplify the
file reading process. A more advanced method would be to read the contacts
into a temporary QMap object, and copy over non-duplicate contacts into
\c contacts.
\snippet examples/addressbook-sdk/part6/addressbook.cpp loadFromFile part3
To display the contacts that have been read from the file, you must first
validate the data obtained to ensure that the file you read from actually
contains address book contacts. If it does, display the first contact;
otherwise, display a QMessageBox to inform you about the problem.
Lastly, connect the \c clicked() signal of the push buttons
with the \c loadFromFile() and \c saveToFile():
\snippet examples/addressbook-sdk/part6/addressbook.cpp connectSlots
*/
/*!
\page tutorials-addressbook-sdk-part7.html
\previouspage Address Book 6 - Loading and Saving
\contentspage {Address Book Tutorial}{Contents}
\example examples/addressbook-sdk/part7
\title Address Book 7 - Additional Features
Although your address book application is useful in its own right, it would
be useful if you could exchange contact data with other applications. The
vCard format is a popular file format that can be used for this purpose. In
this chapter, you extend our address book client to allow contacts to be
exported to vCard \c{.vcf} files.
\section1 Placing Widgets on The Form
Add a push button into our layout by dragging and dropping it in, with
\c exportButton as its \c objectName. The \c toolTip property is set to
\gui{Export as vCard}.
\image addressbook-tutorial-part7-screenshot.png
\section1 The AddressBook Class
Declare a public slot, \c exportAsVCard(), in your header file.
Within the \c AddressBook constructor, connect \c{exportButton}'s
\l{QPushButton::}{clicked()} signal to \c exportAsVCard().
*/
|