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