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

Last change on this file since 321 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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