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

Last change on this file since 651 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

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