source: trunk/doc/src/tutorials/addressbook.qdoc

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 42.1 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the documentation of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:FDL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in a
14** written agreement between you and Nokia.
15**
16** GNU Free Documentation License
17** Alternatively, this file may be used under the terms of the GNU Free
18** Documentation License version 1.3 as published by the Free Software
19** Foundation and appearing in the file included in the packaging of this
20** file.
21**
22** If you have questions regarding the use of this file, please contact
23** Nokia at [email protected].
24** $QT_END_LICENSE$
25**
26****************************************************************************/
27
28/*!
29 \page tutorials-addressbook.html
30
31 \title Address Book Tutorial
32 \brief An introduction to GUI programming, showing how to put together a
33 simple yet fully-functioning application.
34
35 This tutorial is an introduction to GUI programming with the Qt
36 cross-platform framework.
37
38 \image addressbook-tutorial-screenshot.png
39
40 \omit
41 It doesn't cover everything; the emphasis is on teaching the programming
42 philosophy of GUI programming, and Qt's features are introduced as needed.
43 Some commonly used features are never used in this tutorial.
44 \endomit
45
46 In this tutorial, you will learn about some of the basic
47 components of Qt, including:
48
49 \list
50 \o Widgets and layout managers
51 \o Container classes
52 \o Signals and slots
53 \o Input and output devices
54 \endlist
55
56 If you are new to Qt, we recommend reading \l{How to Learn Qt} first.
57
58 Tutorial contents:
59
60 \list 1
61 \o \l{tutorials/addressbook/part1}{Designing the User Interface}
62 \o \l{tutorials/addressbook/part2}{Adding Addresses}
63 \o \l{tutorials/addressbook/part3}{Navigating between Entries}
64 \o \l{tutorials/addressbook/part4}{Editing and Removing Addresses}
65 \o \l{tutorials/addressbook/part5}{Adding a Find Function}
66 \o \l{tutorials/addressbook/part6}{Loading and Saving}
67 \o \l{tutorials/addressbook/part7}{Additional Features}
68 \endlist
69
70 The tutorial source code is located in \c{examples/tutorials/addressbook}.
71
72 Although this little application does not look much like a
73 fully-fledged modern GUI application, it uses many of the basic
74 elements that are used in more complex applications. After you
75 have worked through this tutorial, we recommend reading the
76 \l{mainwindows/application}{Application} example, which presents a
77 small GUI application, with menus, toolbars, a status bar, and so
78 on.
79*/
80
81/*!
82 \page tutorials-addressbook-part1.html
83
84 \example tutorials/addressbook/part1
85 \title Part 1 - Designing the User Interface
86
87 This first part covers the design of the basic graphical user
88 interface (GUI) for our address book application.
89
90 The first step in creating a GUI program is to design the user
91 interface. Here the our goal is to set up the labels and input
92 fields to implement a basic address book. The figure below is a
93 screenshot of the expected output.
94
95 \image addressbook-tutorial-part1-screenshot.png
96
97 We require two QLabel objects, \c nameLabel and \c addressLabel, as well
98 as two input fields, a QLineEdit object, \c nameLine, and a QTextEdit
99 object, \c addressText, to enable the user to enter a contact's name and
100 address. The widgets used and their positions are shown in the figure
101 below.
102
103 \image addressbook-tutorial-part1-labeled-screenshot.png
104
105 There are three files used to implement this address book:
106
107 \list
108 \o \c{addressbook.h} - the definition file for the \c AddressBook
109 class,
110 \o \c{addressbook.cpp} - the implementation file for the
111 \c AddressBook class, and
112 \o \c{main.cpp} - the file containing a \c main() function, with
113 an instance of \c AddressBook.
114 \endlist
115
116 \section1 Qt Programming - Subclassing
117
118 When writing Qt programs, we usually subclass Qt objects to add
119 functionality. This is one of the essential concepts behind creating
120 custom widgets or collections of standard widgets. Subclassing to
121 extend or change the behavior of a widget has the following advantages:
122
123 \list
124 \o We can write implementations of virtual or pure virtual functions to
125 obtain exactly what we need, falling back on the base class's implementation
126 when necessary.
127 \o It allows us to encapsulate parts of the user interface within a class,
128 so that the other parts of the application don't need to know about the
129 individual widgets in the user interface.
130 \o The subclass can be used to create multiple custom widgets in the same
131 application or library, and the code for the subclass can be reused in other
132 projects.
133 \endlist
134
135 Since Qt does not provide a specific address book widget, we subclass a
136 standard Qt widget class and add features to it. The \c AddressBook class
137 we create in this tutorial can be reused in situations where a basic address
138 book widget is needed.
139
140 \section1 Defining the AddressBook Class
141
142 The \l{tutorials/addressbook/part1/addressbook.h}{\c addressbook.h} file is
143 used to define the \c AddressBook class.
144
145 We start by defining \c AddressBook as a QWidget subclass and declaring
146 a constructor. We also use the Q_OBJECT macro to indicate that the class
147 uses internationalization and Qt's signals and slots features, even
148 if we do not use all of these features at this stage.
149
150 \snippet tutorials/addressbook/part1/addressbook.h class definition
151
152 The class holds declarations of \c nameLine and \c addressText,
153 the private instances of QLineEdit and QTextEdit mentioned
154 earlier. The data stored in \c nameLine and \c addressText will
155 be needed for many of the address book functions.
156
157 We don't include declarations of the QLabel objects we will use
158 because we will not need to reference them once they have been
159 created. The way Qt tracks the ownership of objects is explained
160 in the next section.
161
162 The Q_OBJECT macro itself implements some of the more advanced features of Qt.
163 For now, it is useful to think of the Q_OBJECT macro as a shortcut which allows
164 us to use the \l{QObject::}{tr()} and \l{QObject::}{connect()} functions.
165
166 We have now completed the \c addressbook.h file and we move on to
167 implement the corresponding \c addressbook.cpp file.
168
169 \section1 Implementing the AddressBook Class
170
171 The constructor of \c AddressBook accepts a QWidget parameter, \a parent.
172 By convention, we pass this parameter to the base class's constructor.
173 This concept of ownership, where a parent can have one or more children,
174 is useful for grouping widgets in Qt. For example, if you delete a parent,
175 all of its children will be deleted as well.
176
177 \snippet tutorials/addressbook/part1/addressbook.cpp constructor and input fields
178
179 In this constructor, the QLabel objects \c nameLabel and \c
180 addressLabel are instantiated, as well as \c nameLine and \c
181 addressText. The \l{QObject::tr()}{tr()} function returns a
182 translated version of the string, if there is one
183 available. Otherwise it returns the string itself. This function
184 marks its QString parameter as one that should be translated into
185 other languages. It should be used wherever a translatable string
186 appears.
187
188 When programming with Qt, it is useful to know how layouts work.
189 Qt provides three main layout classes: QHBoxLayout, QVBoxLayout
190 and QGridLayout to handle the positioning of widgets.
191
192 \image addressbook-tutorial-part1-labeled-layout.png
193
194 We use a QGridLayout to position our labels and input fields in a
195 structured manner. QGridLayout divides the available space into a grid and
196 places widgets in the cells we specify with row and column numbers. The
197 diagram above shows the layout cells and the position of our widgets, and
198 we specify this arrangement using the following code:
199
200 \snippet tutorials/addressbook/part1/addressbook.cpp layout
201
202 Notice that \c addressLabel is positioned using Qt::AlignTop as an
203 additional argument. This is to make sure it is not vertically centered in
204 cell (1,0). For a basic overview on Qt Layouts, refer to the
205 \l{Layout Management} documentation.
206
207 In order to install the layout object onto the widget, we have to invoke
208 the widget's \l{QWidget::setLayout()}{setLayout()} function:
209
210 \snippet tutorials/addressbook/part1/addressbook.cpp setting the layout
211
212 Lastly, we set the widget's title to "Simple Address Book".
213
214 \section1 Running the Application
215
216 A separate file, \c main.cpp, is used for the \c main() function. Within
217 this function, we instantiate a QApplication object, \c app. QApplication
218 is responsible for various application-wide resources, such as the default
219 font and cursor, and for running an event loop. Hence, there is always one
220 QApplication object in every GUI application using Qt.
221
222 \snippet tutorials/addressbook/part1/main.cpp main function
223
224 We construct a new \c AddressBook widget on the stack and invoke
225 its \l{QWidget::show()}{show()} function to display it.
226 However, the widget will not be shown until the application's event loop
227 is started. We start the event loop by calling the application's
228 \l{QApplication::}{exec()} function; the result returned by this function
229 is used as the return value from the \c main() function. At this point,
230 it becomes apparent why we instanciated \c AddressBook on the stack: It
231 will now go out of scope. Therefore, \c AddressBook and all its child widgets
232 will be deleted, thus preventing memory leaks.
233*/
234
235/*!
236 \page tutorials-addressbook-part2.html
237
238 \example tutorials/addressbook/part2
239 \title Part 2 - Adding Addresses
240
241 The next step in creating the address book is to implement some
242 user interactions.
243
244 \image addressbook-tutorial-part2-add-contact.png
245
246 We will provide a push button that the user can click to add a new contact.
247 Also, some form of data structure is needed to store these contacts in an
248 organized way.
249
250 \section1 Defining the AddressBook Class
251
252 Now that we have the labels and input fields set up, we add push buttons to
253 complete the process of adding a contact. This means that our
254 \c addressbook.h file now has three QPushButton objects declared and three
255 corresponding public slots.
256
257 \snippet tutorials/addressbook/part2/addressbook.h slots
258
259 A slot is a function that responds to a particular signal. We will discuss
260 this concept in further detail when implementing the \c AddressBook class.
261 However, for an overview of Qt's signals and slots concept, you can refer
262 to the \l{Signals and Slots} document.
263
264 Three QPushButton objects (\c addButton, \c submitButton, and
265 \c cancelButton) are now included in our private variable declarations,
266 along with \c nameLine and \c addressText.
267
268 \snippet tutorials/addressbook/part2/addressbook.h pushbutton declaration
269
270 We need a container to store our address book contacts, so that we can
271 traverse and display them. A QMap object, \c contacts, is used for this
272 purpose as it holds a key-value pair: the contact's name as the \e key,
273 and the contact's address as the \e{value}.
274
275 \snippet tutorials/addressbook/part2/addressbook.h remaining private variables
276
277 We also declare two private QString objects, \c oldName and \c oldAddress.
278 These objects are needed to hold the name and address of the contact that
279 was last displayed, before the user clicked \gui Add. So, when the user clicks
280 \gui Cancel, we can revert to displaying the details of the last contact.
281
282 \section1 Implementing the AddressBook Class
283
284 Within the constructor of \c AddressBook, we set the \c nameLine and
285 \c addressText to read-only, so that we can only display but not edit
286 existing contact details.
287
288 \dots
289 \snippet tutorials/addressbook/part2/addressbook.cpp setting readonly 1
290 \dots
291 \snippet tutorials/addressbook/part2/addressbook.cpp setting readonly 2
292
293 Then, we instantiate our push buttons: \c addButton, \c submitButton, and
294 \c cancelButton.
295
296 \snippet tutorials/addressbook/part2/addressbook.cpp pushbutton declaration
297
298 The \c addButton is displayed by invoking the \l{QPushButton::show()}
299 {show()} function, while the \c submitButton and \c cancelButton are
300 hidden by invoking \l{QPushButton::hide()}{hide()}. These two push
301 buttons will only be displayed when the user clicks \gui Add and this is
302 handled by the \c addContact() function discussed below.
303
304 \snippet tutorials/addressbook/part2/addressbook.cpp connecting signals and slots
305
306 We connect the push buttons' \l{QPushButton::clicked()}{clicked()} signal
307 to their respective slots. The figure below illustrates this.
308
309 \image addressbook-tutorial-part2-signals-and-slots.png
310
311 Next, we arrange our push buttons neatly to the right of our address book
312 widget, using a QVBoxLayout to line them up vertically.
313
314 \snippet tutorials/addressbook/part2/addressbook.cpp vertical layout
315
316 The \l{QBoxLayout::addStretch()}{addStretch()} function is used to ensure
317 the push buttons are not evenly spaced, but arranged closer to the top of
318 the widget. The figure below shows the difference between using
319 \l{QBoxLayout::addStretch()}{addStretch()} and not using it.
320
321 \image addressbook-tutorial-part2-stretch-effects.png
322
323 We then add \c buttonLayout1 to \c mainLayout, using
324 \l{QGridLayout::addLayout()}{addLayout()}. This gives us nested layouts
325 as \c buttonLayout1 is now a child of \c mainLayout.
326
327 \snippet tutorials/addressbook/part2/addressbook.cpp grid layout
328
329 Our layout coordinates now look like this:
330
331 \image addressbook-tutorial-part2-labeled-layout.png
332
333 In the \c addContact() function, we store the last displayed contact
334 details in \c oldName and \c oldAddress. Then we clear these input
335 fields and turn off the read-only mode. The focus is set on \c nameLine
336 and we display \c submitButton and \c cancelButton.
337
338 \snippet tutorials/addressbook/part2/addressbook.cpp addContact
339
340 The \c submitContact() function can be divided into three parts:
341
342 \list 1
343 \o We extract the contact's details from \c nameLine and \c addressText
344 and store them in QString objects. We also validate to make sure that the
345 user did not click \gui Submit with empty input fields; otherwise, a
346 QMessageBox is displayed to remind the user for a name and address.
347
348 \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part1
349
350 \o We then proceed to check if the contact already exists. If it does not
351 exist, we add the contact to \c contacts and we display a QMessageBox to
352 inform the user that the contact has been added.
353
354 \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part2
355
356 If the contact already exists, again, we display a QMessageBox to inform
357 the user about this, preventing the user from adding duplicate contacts.
358 Our \c contacts object is based on key-value pairs of name and address,
359 hence, we want to ensure that \e key is unique.
360
361 \o Once we have handled both cases mentioned above, we restore the push
362 buttons to their normal state with the following code:
363
364 \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part3
365
366 \endlist
367
368 The screenshot below shows the QMessageBox object we use to display
369 information messages to the user.
370
371 \image addressbook-tutorial-part2-add-successful.png
372
373 The \c cancel() function restores the last displayed contact details and
374 enables \c addButton, as well as hides \c submitButton and
375 \c cancelButton.
376
377 \snippet tutorials/addressbook/part2/addressbook.cpp cancel
378
379 The general idea behind adding a contact is to give the user the
380 flexibility to click \gui Submit or \gui Cancel at any time. The flowchart below
381 further explains this concept:
382
383 \image addressbook-tutorial-part2-add-flowchart.png
384*/
385
386/*!
387 \page tutorials-addressbook-part3.html
388
389 \example tutorials/addressbook/part3
390 \title Part 3 - Navigating between Entries
391
392 The address book is now about half complete. We should add the
393 capability to navigate among the contacts, but first we must
394 decide what sort of a data structure we need for containing these
395 contacts.
396
397 In the previous section, we used a QMap of key-value pairs with
398 the contact's name as the \e key, and the contact's address as the
399 \e value. This works well for our case. However, in order to
400 navigate and display each entry, a little bit of enhancement is
401 needed.
402
403 We enhance the QMap by making it replicate a data structure similar to a
404 circularly-linked list, where all elements are connected, including the
405 first element and the last element. The figure below illustrates this data
406 structure.
407
408 \image addressbook-tutorial-part3-linkedlist.png
409
410 \section1 Defining the AddressBook Class
411
412 To add navigation functions to the address book, we must add two
413 more slots to the \c AddressBook class: \c next() and \c
414 previous() to the \c addressbook.h file:
415
416 \snippet tutorials/addressbook/part3/addressbook.h navigation functions
417
418 We also require another two QPushButton objects, so we declare \c nextButton
419 and \c previousButton as private variables:
420
421 \snippet tutorials/addressbook/part3/addressbook.h navigation pushbuttons
422
423 \section1 Implementing the AddressBook Class
424
425 In the \c AddressBook constructor in \c addressbook.cpp, we instantiate
426 \c nextButton and \c previousButton and disable them by default. This is
427 because navigation is only enabled when there is more than one contact
428 in the address book.
429
430 \snippet tutorials/addressbook/part3/addressbook.cpp navigation pushbuttons
431
432 We then connect these push buttons to their respective slots:
433
434 \snippet tutorials/addressbook/part3/addressbook.cpp connecting navigation signals
435
436 The image below is the expected graphical user interface.
437
438 \image addressbook-tutorial-part3-screenshot.png
439
440 We follow basic conventions for \c next() and \c previous() functions by
441 placing the \c nextButton on the right and the \c previousButton on the
442 left. In order to achieve this intuitive layout, we use QHBoxLayout to
443 place the widgets side-by-side:
444
445 \snippet tutorials/addressbook/part3/addressbook.cpp navigation layout
446
447 The QHBoxLayout object, \c buttonLayout2, is then added to \c mainLayout.
448
449 \snippet tutorials/addressbook/part3/addressbook.cpp adding navigation layout
450
451 The figure below shows the coordinates of the widgets in \c mainLayout.
452 \image addressbook-tutorial-part3-labeled-layout.png
453
454 Within our \c addContact() function, we have to disable these buttons so
455 that the user does not attempt to navigate while adding a contact.
456
457 \snippet tutorials/addressbook/part3/addressbook.cpp disabling navigation
458
459 Also, in our \c submitContact() function, we enable the navigation
460 buttons, \c nextButton and \c previousButton, depending on the size
461 of \c contacts. As mentioned earlier, navigation is only enabled when
462 there is more than one contact in the address book. The following lines
463 of code demonstrates how to do this:
464
465 \snippet tutorials/addressbook/part3/addressbook.cpp enabling navigation
466
467 We also include these lines of code in the \c cancel() function.
468
469 Recall that we intend to emulate a circularly-linked list with our QMap
470 object, \c contacts. So, in the \c next() function, we obtain an iterator
471 for \c contacts and then:
472
473 \list
474 \o If the iterator is not at the end of \c contacts, we increment it
475 by one.
476 \o If the iterator is at the end of \c contacts, we move it to the
477 beginning of \c contacts. This gives us the illusion that our QMap is
478 working like a circularly-linked list.
479 \endlist
480
481 \snippet tutorials/addressbook/part3/addressbook.cpp next() function
482
483 Once we have iterated to the correct object in \c contacts, we display
484 its contents on \c nameLine and \c addressText.
485
486 Similarly, for the \c previous() function, we obtain an iterator for
487 \c contacts and then:
488
489 \list
490 \o If the iterator is at the end of \c contacts, we clear the
491 display and return.
492 \o If the iterator is at the beginning of \c contacts, we move it to
493 the end.
494 \o We then decrement the iterator by one.
495 \endlist
496
497 \snippet tutorials/addressbook/part3/addressbook.cpp previous() function
498
499 Again, we display the contents of the current object in \c contacts.
500
501*/
502
503/*!
504 \page tutorials-addressbook-part4.html
505
506 \example tutorials/addressbook/part4
507 \title Part 4 - Editing and Removing Addresses
508
509 Now we look at ways to modify the contents of contacts stored in
510 the address book.
511
512 \image addressbook-tutorial-screenshot.png
513
514 We now have an address book that not only holds contacts in an
515 organized manner, but also allows navigation. It would be
516 convenient to include edit and remove functions so that a
517 contact's details can be changed when needed. However, this
518 requires a little improvement, in the form of enums. We defined
519 two modes: \c{AddingMode} and \c{NavigationMode}, but they were
520 not defined as enum values. Instead, we enabled and disabled the
521 corresponding buttons manually, resulting in multiple lines of
522 repeated code.
523
524 Here we define the \c Mode enum with three different values:
525
526 \list
527 \o \c{NavigationMode},
528 \o \c{AddingMode}, and
529 \o \c{EditingMode}.
530 \endlist
531
532 \section1 Defining the AddressBook Class
533
534 The \c addressbook.h file is updated to contain the \c Mode enum:
535
536 \snippet tutorials/addressbook/part4/addressbook.h Mode enum
537
538 We also add two new slots, \c editContact() and \c removeContact(), to
539 our current list of public slots.
540
541 \snippet tutorials/addressbook/part4/addressbook.h edit and remove slots
542
543 In order to switch between modes, we introduce the \c updateInterface() function
544 to control the enabling and disabling of all QPushButton objects. We also
545 add two new push buttons, \c editButton and \c removeButton, for the edit
546 and remove functions mentioned earlier.
547
548 \snippet tutorials/addressbook/part4/addressbook.h updateInterface() declaration
549 \dots
550 \snippet tutorials/addressbook/part4/addressbook.h buttons declaration
551 \dots
552 \snippet tutorials/addressbook/part4/addressbook.h mode declaration
553
554 Lastly, we declare \c currentMode to keep track of the enum's current mode.
555
556 \section1 Implementing the AddressBook Class
557
558 We now implement the mode-changing features of the address
559 book. The \c editButton and \c removeButton are instantiated and
560 disabled by default. The address book starts with zero contacts
561 in memory.
562
563 \snippet tutorials/addressbook/part4/addressbook.cpp edit and remove buttons
564
565 These buttons are then connected to their respective slots, \c editContact()
566 and \c removeContact(), and we add them to \c buttonLayout1.
567
568 \snippet tutorials/addressbook/part4/addressbook.cpp connecting edit and remove
569 \dots
570 \snippet tutorials/addressbook/part4/addressbook.cpp adding edit and remove to the layout
571
572 The \c editContact() function stores the contact's old details in
573 \c oldName and \c oldAddress, before switching the mode to \c EditingMode.
574 In this mode, the \c submitButton and \c cancelButton are both enabled,
575 hence, the user can change the contact's details and click either button.
576
577 \snippet tutorials/addressbook/part4/addressbook.cpp editContact() function
578
579 The \c submitContact() function has been divided in two with an \c{if-else}
580 statement. We check \c currentMode to see if it's in \c AddingMode. If it is,
581 we proceed with our adding process.
582
583 \snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function beginning
584 \dots
585 \snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function part1
586
587 Otherwise, we check to see if \c currentMode is in \c EditingMode. If it
588 is, we compare \c oldName with \c name. If the name has changed, we remove
589 the old contact from \c contacts and insert the newly updated contact.
590
591 \snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function part2
592
593 If only the address has changed (i.e., \c oldAddress is not the same as \c address),
594 we update the contact's address. Lastly, we set \c currentMode to
595 \c NavigationMode. This is an important step as it re-enables all the
596 disabled push buttons.
597
598 To remove a contact from the address book, we implement the
599 \c removeContact() function. This function checks to see if the contact
600 exists in \c contacts.
601
602 \snippet tutorials/addressbook/part4/addressbook.cpp removeContact() function
603
604 If it does, we display a QMessageBox, to confirm the removal with the
605 user. Once the user has confirmed, we call \c previous() to ensure that the
606 user interface shows another contact, and we remove the contact using \l{QMap}'s
607 \l{QMap::remove()}{remove()} function. As a courtesy, we display a QMessageBox
608 to inform the user. Both the message boxes used in this function are shown below:
609
610 \image addressbook-tutorial-part4-remove.png
611
612 \section2 Updating the User Interface
613
614 We mentioned the \c updateInterface() function earlier as a means to
615 enable and disable the push buttons depending on the current mode.
616 The function updates the current mode according to the \c mode argument
617 passed to it, assigning it to \c currentMode before checking its value.
618
619 Each of the push buttons is then enabled or disabled, depending on the
620 current mode. The code for \c AddingMode and \c EditingMode is shown below:
621
622 \snippet tutorials/addressbook/part4/addressbook.cpp update interface() part 1
623
624 For \c NavigationMode, however, we include conditions within the parameters
625 of the QPushButton::setEnabled() function. This is to ensure that
626 \c editButton and \c removeButton are enabled when there is at least one
627 contact in the address book; \c nextButton and \c previousButton are only
628 enabled when there is more than one contact in the address book.
629
630 \snippet tutorials/addressbook/part4/addressbook.cpp update interface() part 2
631
632 By setting the mode and updating the user interface in the same
633 function, we avoid the possibility of the user interface getting
634 out of sync with the internal state of the application.
635 */
636
637/*!
638 \page tutorials-addressbook-part5.html
639
640 \example tutorials/addressbook/part5
641 \title Part 5 - Adding a Find Function
642
643 Here we look at ways to locate contacts and addresses in the
644 address book.
645
646 \image addressbook-tutorial-part5-screenshot.png
647
648 As we add contacts to our address book, it becomes tedious to
649 navigate the list with the \e Next and \e Previous buttons. A \e
650 Find function would be more efficient. The screenshot above shows
651 the \e Find button and its position on the panel of buttons.
652
653 When the user clicks on the \e Find button, it is useful to
654 display a dialog that prompts for a contact's name. Qt provides
655 QDialog, which we subclass here to implement a \c FindDialog
656 class.
657
658 \section1 Defining the FindDialog Class
659
660 \image addressbook-tutorial-part5-finddialog.png
661
662 In order to subclass QDialog, we first include the header for QDialog in
663 the \c finddialog.h file. Also, we use forward declaration to declare
664 QLineEdit and QPushButton since we will be using those widgets in our
665 dialog class.
666
667 As in our \c AddressBook class, the \c FindDialog class includes
668 the Q_OBJECT macro and its constructor is defined to accept a parent
669 QWidget, even though the dialog will be opened as a separate window.
670
671 \snippet tutorials/addressbook/part5/finddialog.h FindDialog header
672
673 We define a public function, \c getFindText(), to be used by classes that
674 instantiate \c FindDialog. This function allows these classes to obtain the
675 search string entered by the user. A public slot, \c findClicked(), is also
676 defined to handle the search string when the user clicks the \gui Find
677 button.
678
679 Lastly, we define the private variables, \c findButton, \c lineEdit
680 and \c findText, corresponding to the \gui Find button, the line edit
681 into which the user types the search string, and an internal string
682 used to store the search string for later use.
683
684 \section1 Implementing the FindDialog Class
685
686 Within the constructor of \c FindDialog, we set up the private variables,
687 \c lineEdit, \c findButton and \c findText. We use a QHBoxLayout to
688 position the widgets.
689
690 \snippet tutorials/addressbook/part5/finddialog.cpp constructor
691
692 We set the layout and window title, as well as connect the signals to their
693 respective slots. Notice that \c{findButton}'s \l{QPushButton::clicked()}
694 {clicked()} signal is connected to to \c findClicked() and
695 \l{QDialog::accept()}{accept()}. The \l{QDialog::accept()}{accept()} slot
696 provided by QDialog hides the dialog and sets the result code to
697 \l{QDialog::}{Accepted}. We use this function to help \c{AddressBook}'s
698 \c findContact() function know when the \c FindDialog object has been
699 closed. We will explain this logic in further detail when discussing the
700 \c findContact() function.
701
702 \image addressbook-tutorial-part5-signals-and-slots.png
703
704 In \c findClicked(), we validate \c lineEdit to ensure that the user
705 did not click the \gui Find button without entering a contact's name. Then, we set
706 \c findText to the search string, extracted from \c lineEdit. After that,
707 we clear the contents of \c lineEdit and hide the dialog.
708
709 \snippet tutorials/addressbook/part5/finddialog.cpp findClicked() function
710
711 The \c findText variable has a public getter function, \c getFindText(),
712 associated with it. Since we only ever set \c findText directly in both the
713 constructor and in the \c findClicked() function, we do not create a
714 setter function to accompany \c getFindText().
715 Because \c getFindText() is public, classes instantiating and using
716 \c FindDialog can always access the search string that the user has
717 entered and accepted.
718
719 \snippet tutorials/addressbook/part5/finddialog.cpp getFindText() function
720
721 \section1 Defining the AddressBook Class
722
723 To ensure we can use \c FindDialog from within our \c AddressBook class, we
724 include \c finddialog.h in the \c addressbook.h file.
725
726 \snippet tutorials/addressbook/part5/addressbook.h include finddialog's header
727
728 So far, all our address book features have a QPushButton and a
729 corresponding slot. Similarly, for the \gui Find feature we have
730 \c findButton and \c findContact().
731
732 The \c findButton is declared as a private variable and the
733 \c findContact() function is declared as a public slot.
734
735 \snippet tutorials/addressbook/part5/addressbook.h findContact() declaration
736 \dots
737 \snippet tutorials/addressbook/part5/addressbook.h findButton declaration
738
739 Lastly, we declare the private variable, \c dialog, which we will use to
740 refer to an instance of \c FindDialog.
741
742 \snippet tutorials/addressbook/part5/addressbook.h FindDialog declaration
743
744 Once we have instantiated a dialog, we will want to use it more than once;
745 using a private variable allows us to refer to it from more than one place
746 in the class.
747
748 \section1 Implementing the AddressBook Class
749
750 Within the \c AddressBook class's constructor, we instantiate our private
751 objects, \c findButton and \c findDialog:
752
753 \snippet tutorials/addressbook/part5/addressbook.cpp instantiating findButton
754 \dots
755 \snippet tutorials/addressbook/part5/addressbook.cpp instantiating FindDialog
756
757 Next, we connect the \c{findButton}'s
758 \l{QPushButton::clicked()}{clicked()} signal to \c findContact().
759
760 \snippet tutorials/addressbook/part5/addressbook.cpp signals and slots for find
761
762 Now all that is left is the code for our \c findContact() function:
763
764 \snippet tutorials/addressbook/part5/addressbook.cpp findContact() function
765
766 We start out by displaying the \c FindDialog instance, \c dialog. This is
767 when the user enters a contact name to look up. Once the user clicks
768 the dialog's \c findButton, the dialog is hidden and the result code is
769 set to QDialog::Accepted. This ensures that
770 our \c if statement is always true.
771
772 We then proceed to extract the search string, which in this case is
773 \c contactName, using \c{FindDialog}'s \c getFindText() function. If the
774 contact exists in our address book, we display it immediately. Otherwise,
775 we display the QMessageBox shown below to indicate that their search
776 failed.
777
778 \image addressbook-tutorial-part5-notfound.png
779*/
780
781/*!
782 \page tutorials-addressbook-part6.html
783
784 \example tutorials/addressbook/part6
785 \title Part 6 - Loading and Saving
786
787 This part covers the Qt file handling features we use to write
788 loading and saving routines for the address book.
789
790 \image addressbook-tutorial-part6-screenshot.png
791
792 Although browsing and searching the contact list are useful
793 features, our address book is not complete until we can save
794 existing contacts and load them again at a later time.
795
796 Qt provides a number of classes for \l{Input/Output and Networking}
797 {input and output}, but we have chosen to use two which are simple to use
798 in combination: QFile and QDataStream.
799
800 A QFile object represents a file on disk that can be read from and written
801 to. QFile is a subclass of the more general QIODevice class which
802 represents many different kinds of devices.
803
804 A QDataStream object is used to serialize binary data so that it can be
805 stored in a QIODevice and retrieved again later. Reading from a QIODevice
806 and writing to it is as simple as opening the stream - with the respective
807 device as a parameter - and reading from or writing to it.
808
809
810 \section1 Defining the AddressBook Class
811
812 We declare two public slots, \c saveToFile() and \c loadFromFile(), as well
813 as two QPushButton objects, \c loadButton and \c saveButton.
814
815 \snippet tutorials/addressbook/part6/addressbook.h save and load functions declaration
816 \dots
817 \snippet tutorials/addressbook/part6/addressbook.h save and load buttons declaration
818
819 \section1 Implementing the AddressBook Class
820
821 In our constructor, we instantiate \c loadButton and \c saveButton.
822 Ideally, it would be more user-friendly to set the push buttons' labels
823 to "Load contacts from a file" and "Save contacts to a file". However, due
824 to the size of our other push buttons, we set the labels to \gui{Load...}
825 and \gui{Save...}. Fortunately, Qt provides a simple way to set tooltips with
826 \l{QWidget::setToolTip()}{setToolTip()} and we use it in the following way
827 for our push buttons:
828
829 \snippet tutorials/addressbook/part6/addressbook.cpp tooltip 1
830 \dots
831 \snippet tutorials/addressbook/part6/addressbook.cpp tooltip 2
832
833 Although it is not shown here, just like the other features we implemented,
834 we add the push buttons to the layout panel on the right, \c button1Layout,
835 and we connect the push buttons' \l{QPushButton::clicked()}{clicked()}
836 signals to their respective slots.
837
838 For the saving feature, we first obtain \c fileName using
839 QFileDialog::getSaveFileName(). This is a convenience function provided
840 by QFileDialog, which pops up a modal file dialog and allows the user to
841 enter a file name or select any existing \c{.abk} file. The \c{.abk} file
842 is our Address Book extension that we create when we save contacts.
843
844 \snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part1
845
846 The file dialog that pops up is displayed in the screenshot below:
847
848 \image addressbook-tutorial-part6-save.png
849
850 If \c fileName is not empty, we create a QFile object, \c file, with
851 \c fileName. QFile works with QDataStream as QFile is a QIODevice.
852
853 Next, we attempt to open the file in \l{QIODevice::}{WriteOnly} mode.
854 If this is unsuccessful, we display a QMessageBox to inform the user.
855
856 \snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part2
857
858 Otherwise, we instantiate a QDataStream object, \c out, to write the open
859 file. QDataStream requires that the same version of the stream is used
860 for reading and writing. We ensure that this is the case by setting the
861 version used to the \l{QDataStream::Qt_4_5}{version introduced with Qt 4.5}
862 before serializing the data to \c file.
863
864 \snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part3
865
866 For the loading feature, we also obtain \c fileName using
867 QFileDialog::getOpenFileName(). This function, the counterpart to
868 QFileDialog::getSaveFileName(), also pops up the modal file dialog and
869 allows the user to enter a file name or select any existing \c{.abk} file
870 to load it into the address book.
871
872 \snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part1
873
874 On Windows, for example, this function pops up a native file dialog, as
875 shown in the following screenshot.
876
877 \image addressbook-tutorial-part6-load.png
878
879 If \c fileName is not empty, again, we use a QFile object, \c file, and
880 attempt to open it in \l{QIODevice::}{ReadOnly} mode. Similar to our
881 implementation of \c saveToFile(), if this attempt is unsuccessful, we
882 display a QMessageBox to inform the user.
883
884 \snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part2
885
886 Otherwise, we instantiate a QDataStream object, \c in, set its version as
887 above and read the serialized data into the \c contacts data structure.
888 The \c contacts object is emptied before data is read into it to simplify
889 the file reading process. A more advanced method would be to read the
890 contacts into a temporary QMap object, and copy over non-duplicate contacts
891 into \c contacts.
892
893 \snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part3
894
895 To display the contacts that have been read from the file, we must first
896 validate the data obtained to ensure that the file we read from actually
897 contains address book contacts. If it does, we display the first contact;
898 otherwise, we display a QMessageBox to inform the user about the problem.
899 Lastly, we update the interface to enable and disable the push buttons
900 accordingly.
901*/
902
903/*!
904 \page tutorials-addressbook-part7.html
905
906 \example tutorials/addressbook/part7
907 \title Part 7 - Additional Features
908
909 This part covers some additional features that make the address
910 book more convenient for the frequent user.
911
912 \image addressbook-tutorial-part7-screenshot.png
913
914 Although our address book is useful in isolation, it would be
915 better if we could exchange contact data with other applications.
916 The vCard format is a popular file format that can be used for
917 this purpose. Here we extend our address book client to allow
918 contacts to be exported to vCard \c{.vcf} files.
919
920 \section1 Defining the AddressBook Class
921
922 We add a QPushButton object, \c exportButton, and a corresponding public
923 slot, \c exportAsVCard() to our \c AddressBook class in the
924 \c addressbook.h file.
925
926 \snippet tutorials/addressbook/part7/addressbook.h exportAsVCard() declaration
927 \dots
928 \snippet tutorials/addressbook/part7/addressbook.h exportButton declaration
929
930 \section1 Implementing the AddressBook Class
931
932 Within the \c AddressBook constructor, we connect \c{exportButton}'s
933 \l{QPushButton::clicked()}{clicked()} signal to \c exportAsVCard().
934 We also add this button to our \c buttonLayout1, the layout responsible
935 for our panel of buttons on the right.
936
937 In our \c exportAsVCard() function, we start by extracting the contact's
938 name into \c name. We declare \c firstName, \c lastName and \c nameList.
939 Next, we look for the index of the first white space in \c name. If there
940 is a white space, we split the contact's name into \c firstName and
941 \c lastName. Then, we replace the space with an underscore ("_").
942 Alternately, if there is no white space, we assume that the contact only
943 has a first name.
944
945 \snippet tutorials/addressbook/part7/addressbook.cpp export function part1
946
947 As with the \c saveToFile() function, we open a file dialog to let the user
948 choose a location for the file. Using the file name chosen, we create an
949 instance of QFile to write to.
950
951 We attempt to open the file in \l{QIODevice::}{WriteOnly} mode. If this
952 process fails, we display a QMessageBox to inform the user about the
953 problem and return. Otherwise, we pass the file as a parameter to a
954 QTextStream object, \c out. Like QDataStream, the QTextStream class
955 provides functionality to read and write plain text to files. As a result,
956 the \c{.vcf} file generated can be opened for editing in a text editor.
957
958 \snippet tutorials/addressbook/part7/addressbook.cpp export function part2
959
960 We then write out a vCard file with the \c{BEGIN:VCARD} tag, followed by
961 the \c{VERSION:2.1} tag. The contact's name is written with the \c{N:}
962 tag. For the \c{FN:} tag, which fills in the "File as" property of a vCard,
963 we have to check whether the contact has a last name or not. If the contact
964 does, we use the details in \c nameList to fill it. Otherwise, we write
965 \c firstName only.
966
967 \snippet tutorials/addressbook/part7/addressbook.cpp export function part3
968
969 We proceed to write the contact's address. The semicolons in the address
970 are escaped with "\\", the newlines are replaced with semicolons, and the
971 commas are replaced with spaces. Lastly, we write the \c{ADR;HOME:;}
972 tag, followed by \c address and then the \c{END:VCARD} tag.
973
974 \snippet tutorials/addressbook/part7/addressbook.cpp export function part4
975
976 In the end, a QMessageBox is displayed to inform the user that the vCard
977 has been successfully exported.
978
979 \e{vCard is a trademark of the \l{http://www.imc.org}
980 {Internet Mail Consortium}}.
981*/
Note: See TracBrowser for help on using the repository browser.