1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the documentation of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:FDL$
9 ** GNU Free Documentation License
10 ** Alternatively, this file may be used under the terms of the GNU Free
11 ** Documentation License version 1.3 as published by the Free Software
12 ** Foundation and appearing in the file included in the packaging of
16 ** Alternatively, this file may be used in accordance with the terms
17 ** 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 \li Widgets and layout managers
53 \li Input and output devices
59 \li \l{tutorials/addressbook/part1}{Designing the User Interface}
60 \li \l{tutorials/addressbook/part2}{Adding Addresses}
61 \li \l{tutorials/addressbook/part3}{Navigating between Entries}
62 \li \l{tutorials/addressbook/part4}{Editing and Removing Addresses}
63 \li \l{tutorials/addressbook/part5}{Adding a Find Function}
64 \li \l{tutorials/addressbook/part6}{Loading and Saving}
65 \li \l{tutorials/addressbook/part7}{Additional Features}
68 The tutorial source code is located in \c{examples/tutorials/addressbook}.
70 Although this little application does not look much like a
71 fully-fledged modern GUI application, it uses many of the basic
72 elements that are used in more complex applications. After you
73 have worked through this tutorial, we recommend reading the
74 \l{mainwindows/application}{Application} example, which presents a
75 small GUI application, with menus, toolbars, a status bar, and so
80 \page tutorials-addressbook-part1.html
82 \example tutorials/addressbook/part1
83 \title Part 1 - Designing the User Interface
85 This first part covers the design of the basic graphical user
86 interface (GUI) for our address book application.
88 The first step in creating a GUI program is to design the user
89 interface. Here the our goal is to set up the labels and input
90 fields to implement a basic address book. The figure below is a
91 screenshot of the expected output.
93 \image addressbook-tutorial-part1-screenshot.png
95 We require two QLabel objects, \c nameLabel and \c addressLabel, as well
96 as two input fields, a QLineEdit object, \c nameLine, and a QTextEdit
97 object, \c addressText, to enable the user to enter a contact's name and
98 address. The widgets used and their positions are shown in the figure
101 \image addressbook-tutorial-part1-labeled-screenshot.png
103 There are three files used to implement this address book:
106 \li \c{addressbook.h} - the definition file for the \c AddressBook
108 \li \c{addressbook.cpp} - the implementation file for the
109 \c AddressBook class, and
110 \li \c{main.cpp} - the file containing a \c main() function, with
111 an instance of \c AddressBook.
114 \section1 Qt Programming - Subclassing
116 When writing Qt programs, we usually subclass Qt objects to add
117 functionality. This is one of the essential concepts behind creating
118 custom widgets or collections of standard widgets. Subclassing to
119 extend or change the behavior of a widget has the following advantages:
122 \li We can write implementations of virtual or pure virtual functions to
123 obtain exactly what we need, falling back on the base class's implementation
125 \li It allows us to encapsulate parts of the user interface within a class,
126 so that the other parts of the application don't need to know about the
127 individual widgets in the user interface.
128 \li The subclass can be used to create multiple custom widgets in the same
129 application or library, and the code for the subclass can be reused in other
133 Since Qt does not provide a specific address book widget, we subclass a
134 standard Qt widget class and add features to it. The \c AddressBook class
135 we create in this tutorial can be reused in situations where a basic address
136 book widget is needed.
138 \section1 Defining the AddressBook Class
140 The \l{tutorials/addressbook/part1/addressbook.h}{\c addressbook.h} file is
141 used to define the \c AddressBook class.
143 We start by defining \c AddressBook as a QWidget subclass and declaring
144 a constructor. We also use the Q_OBJECT macro to indicate that the class
145 uses internationalization and Qt's signals and slots features, even
146 if we do not use all of these features at this stage.
148 \snippet tutorials/addressbook/part1/addressbook.h class definition
150 The class holds declarations of \c nameLine and \c addressText,
151 the private instances of QLineEdit and QTextEdit mentioned
152 earlier. The data stored in \c nameLine and \c addressText will
153 be needed for many of the address book functions.
155 We don't include declarations of the QLabel objects we will use
156 because we will not need to reference them once they have been
157 created. The way Qt tracks the ownership of objects is explained
160 The Q_OBJECT macro itself implements some of the more advanced features of Qt.
161 For now, it is useful to think of the Q_OBJECT macro as a shortcut which allows
162 us to use the \l{QObject::}{tr()} and \l{QObject::}{connect()} functions.
164 We have now completed the \c addressbook.h file and we move on to
165 implement the corresponding \c addressbook.cpp file.
167 \section1 Implementing the AddressBook Class
169 The constructor of \c AddressBook accepts a QWidget parameter, \a parent.
170 By convention, we pass this parameter to the base class's constructor.
171 This concept of ownership, where a parent can have one or more children,
172 is useful for grouping widgets in Qt. For example, if you delete a parent,
173 all of its children will be deleted as well.
175 \snippet tutorials/addressbook/part1/addressbook.cpp constructor and input fields
177 In this constructor, the QLabel objects \c nameLabel and \c
178 addressLabel are instantiated, as well as \c nameLine and \c
179 addressText. The \l{QObject::tr()}{tr()} function returns a
180 translated version of the string, if there is one
181 available. Otherwise it returns the string itself. This function
182 marks its QString parameter as one that should be translated into
183 other languages. It should be used wherever a translatable string
186 When programming with Qt, it is useful to know how layouts work.
187 Qt provides three main layout classes: QHBoxLayout, QVBoxLayout
188 and QGridLayout to handle the positioning of widgets.
190 \image addressbook-tutorial-part1-labeled-layout.png
192 We use a QGridLayout to position our labels and input fields in a
193 structured manner. QGridLayout divides the available space into a grid and
194 places widgets in the cells we specify with row and column numbers. The
195 diagram above shows the layout cells and the position of our widgets, and
196 we specify this arrangement using the following code:
198 \snippet tutorials/addressbook/part1/addressbook.cpp layout
200 Notice that \c addressLabel is positioned using Qt::AlignTop as an
201 additional argument. This is to make sure it is not vertically centered in
202 cell (1,0). For a basic overview on Qt Layouts, refer to the
203 \l{Layout Management} documentation.
205 In order to install the layout object onto the widget, we have to invoke
206 the widget's \l{QWidget::setLayout()}{setLayout()} function:
208 \snippet tutorials/addressbook/part1/addressbook.cpp setting the layout
210 Lastly, we set the widget's title to "Simple Address Book".
212 \section1 Running the Application
214 A separate file, \c main.cpp, is used for the \c main() function. Within
215 this function, we instantiate a QApplication object, \c app. QApplication
216 is responsible for various application-wide resources, such as the default
217 font and cursor, and for running an event loop. Hence, there is always one
218 QApplication object in every GUI application using Qt.
220 \snippet tutorials/addressbook/part1/main.cpp main function
222 We construct a new \c AddressBook widget on the stack and invoke
223 its \l{QWidget::show()}{show()} function to display it.
224 However, the widget will not be shown until the application's event loop
225 is started. We start the event loop by calling the application's
226 \l{QApplication::}{exec()} function; the result returned by this function
227 is used as the return value from the \c main() function. At this point,
228 it becomes apparent why we instanciated \c AddressBook on the stack: It
229 will now go out of scope. Therefore, \c AddressBook and all its child widgets
230 will be deleted, thus preventing memory leaks.
234 \page tutorials-addressbook-part2.html
236 \example tutorials/addressbook/part2
237 \title Part 2 - Adding Addresses
239 The next step in creating the address book is to implement some
242 \image addressbook-tutorial-part2-add-contact.png
244 We will provide a push button that the user can click to add a new contact.
245 Also, some form of data structure is needed to store these contacts in an
248 \section1 Defining the AddressBook Class
250 Now that we have the labels and input fields set up, we add push buttons to
251 complete the process of adding a contact. This means that our
252 \c addressbook.h file now has three QPushButton objects declared and three
253 corresponding public slots.
255 \snippet tutorials/addressbook/part2/addressbook.h slots
257 A slot is a function that responds to a particular signal. We will discuss
258 this concept in further detail when implementing the \c AddressBook class.
259 However, for an overview of Qt's signals and slots concept, you can refer
260 to the \l{Signals and Slots} document.
262 Three QPushButton objects (\c addButton, \c submitButton, and
263 \c cancelButton) are now included in our private variable declarations,
264 along with \c nameLine and \c addressText.
266 \snippet tutorials/addressbook/part2/addressbook.h pushbutton declaration
268 We need a container to store our address book contacts, so that we can
269 traverse and display them. A QMap object, \c contacts, is used for this
270 purpose as it holds a key-value pair: the contact's name as the \e key,
271 and the contact's address as the \e{value}.
273 \snippet tutorials/addressbook/part2/addressbook.h remaining private variables
275 We also declare two private QString objects, \c oldName and \c oldAddress.
276 These objects are needed to hold the name and address of the contact that
277 was last displayed, before the user clicked \uicontrol Add. So, when the user clicks
278 \uicontrol Cancel, we can revert to displaying the details of the last contact.
280 \section1 Implementing the AddressBook Class
282 Within the constructor of \c AddressBook, we set the \c nameLine and
283 \c addressText to read-only, so that we can only display but not edit
284 existing contact details.
287 \snippet tutorials/addressbook/part2/addressbook.cpp setting readonly 1
289 \snippet tutorials/addressbook/part2/addressbook.cpp setting readonly 2
291 Then, we instantiate our push buttons: \c addButton, \c submitButton, and
294 \snippet tutorials/addressbook/part2/addressbook.cpp pushbutton declaration
296 The \c addButton is displayed by invoking the \l{QPushButton::show()}
297 {show()} function, while the \c submitButton and \c cancelButton are
298 hidden by invoking \l{QPushButton::hide()}{hide()}. These two push
299 buttons will only be displayed when the user clicks \uicontrol Add and this is
300 handled by the \c addContact() function discussed below.
302 \snippet tutorials/addressbook/part2/addressbook.cpp connecting signals and slots
304 We connect the push buttons' \l{QPushButton::clicked()}{clicked()} signal
305 to their respective slots. The figure below illustrates this.
307 \image addressbook-tutorial-part2-signals-and-slots.png
309 Next, we arrange our push buttons neatly to the right of our address book
310 widget, using a QVBoxLayout to line them up vertically.
312 \snippet tutorials/addressbook/part2/addressbook.cpp vertical layout
314 The \l{QBoxLayout::addStretch()}{addStretch()} function is used to ensure
315 the push buttons are not evenly spaced, but arranged closer to the top of
316 the widget. The figure below shows the difference between using
317 \l{QBoxLayout::addStretch()}{addStretch()} and not using it.
319 \image addressbook-tutorial-part2-stretch-effects.png
321 We then add \c buttonLayout1 to \c mainLayout, using
322 \l{QGridLayout::addLayout()}{addLayout()}. This gives us nested layouts
323 as \c buttonLayout1 is now a child of \c mainLayout.
325 \snippet tutorials/addressbook/part2/addressbook.cpp grid layout
327 Our layout coordinates now look like this:
329 \image addressbook-tutorial-part2-labeled-layout.png
331 In the \c addContact() function, we store the last displayed contact
332 details in \c oldName and \c oldAddress. Then we clear these input
333 fields and turn off the read-only mode. The focus is set on \c nameLine
334 and we display \c submitButton and \c cancelButton.
336 \snippet tutorials/addressbook/part2/addressbook.cpp addContact
338 The \c submitContact() function can be divided into three parts:
341 \li We extract the contact's details from \c nameLine and \c addressText
342 and store them in QString objects. We also validate to make sure that the
343 user did not click \uicontrol Submit with empty input fields; otherwise, a
344 QMessageBox is displayed to remind the user for a name and address.
346 \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part1
348 \li We then proceed to check if the contact already exists. If it does not
349 exist, we add the contact to \c contacts and we display a QMessageBox to
350 inform the user that the contact has been added.
352 \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part2
354 If the contact already exists, again, we display a QMessageBox to inform
355 the user about this, preventing the user from adding duplicate contacts.
356 Our \c contacts object is based on key-value pairs of name and address,
357 hence, we want to ensure that \e key is unique.
359 \li Once we have handled both cases mentioned above, we restore the push
360 buttons to their normal state with the following code:
362 \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part3
366 The screenshot below shows the QMessageBox object we use to display
367 information messages to the user.
369 \image addressbook-tutorial-part2-add-successful.png
371 The \c cancel() function restores the last displayed contact details and
372 enables \c addButton, as well as hides \c submitButton and
375 \snippet tutorials/addressbook/part2/addressbook.cpp cancel
377 The general idea behind adding a contact is to give the user the
378 flexibility to click \uicontrol Submit or \uicontrol Cancel at any time. The flowchart below
379 further explains this concept:
381 \image addressbook-tutorial-part2-add-flowchart.png
385 \page tutorials-addressbook-part3.html
387 \example tutorials/addressbook/part3
388 \title Part 3 - Navigating between Entries
390 The address book is now about half complete. We should add the
391 capability to navigate among the contacts, but first we must
392 decide what sort of a data structure we need for containing these
395 In the previous section, we used a QMap of key-value pairs with
396 the contact's name as the \e key, and the contact's address as the
397 \e value. This works well for our case. However, in order to
398 navigate and display each entry, a little bit of enhancement is
401 We enhance the QMap by making it replicate a data structure similar to a
402 circularly-linked list, where all elements are connected, including the
403 first element and the last element. The figure below illustrates this data
406 \image addressbook-tutorial-part3-linkedlist.png
408 \section1 Defining the AddressBook Class
410 To add navigation functions to the address book, we must add two
411 more slots to the \c AddressBook class: \c next() and \c
412 previous() to the \c addressbook.h file:
414 \snippet tutorials/addressbook/part3/addressbook.h navigation functions
416 We also require another two QPushButton objects, so we declare \c nextButton
417 and \c previousButton as private variables:
419 \snippet tutorials/addressbook/part3/addressbook.h navigation pushbuttons
421 \section1 Implementing the AddressBook Class
423 In the \c AddressBook constructor in \c addressbook.cpp, we instantiate
424 \c nextButton and \c previousButton and disable them by default. This is
425 because navigation is only enabled when there is more than one contact
428 \snippet tutorials/addressbook/part3/addressbook.cpp navigation pushbuttons
430 We then connect these push buttons to their respective slots:
432 \snippet tutorials/addressbook/part3/addressbook.cpp connecting navigation signals
434 The image below is the expected graphical user interface.
436 \image addressbook-tutorial-part3-screenshot.png
438 We follow basic conventions for \c next() and \c previous() functions by
439 placing the \c nextButton on the right and the \c previousButton on the
440 left. In order to achieve this intuitive layout, we use QHBoxLayout to
441 place the widgets side-by-side:
443 \snippet tutorials/addressbook/part3/addressbook.cpp navigation layout
445 The QHBoxLayout object, \c buttonLayout2, is then added to \c mainLayout.
447 \snippet tutorials/addressbook/part3/addressbook.cpp adding navigation layout
449 The figure below shows the coordinates of the widgets in \c mainLayout.
450 \image addressbook-tutorial-part3-labeled-layout.png
452 Within our \c addContact() function, we have to disable these buttons so
453 that the user does not attempt to navigate while adding a contact.
455 \snippet tutorials/addressbook/part3/addressbook.cpp disabling navigation
457 Also, in our \c submitContact() function, we enable the navigation
458 buttons, \c nextButton and \c previousButton, depending on the size
459 of \c contacts. As mentioned earlier, navigation is only enabled when
460 there is more than one contact in the address book. The following lines
461 of code demonstrates how to do this:
463 \snippet tutorials/addressbook/part3/addressbook.cpp enabling navigation
465 We also include these lines of code in the \c cancel() function.
467 Recall that we intend to emulate a circularly-linked list with our QMap
468 object, \c contacts. So, in the \c next() function, we obtain an iterator
469 for \c contacts and then:
472 \li If the iterator is not at the end of \c contacts, we increment it
474 \li If the iterator is at the end of \c contacts, we move it to the
475 beginning of \c contacts. This gives us the illusion that our QMap is
476 working like a circularly-linked list.
479 \snippet tutorials/addressbook/part3/addressbook.cpp next() function
481 Once we have iterated to the correct object in \c contacts, we display
482 its contents on \c nameLine and \c addressText.
484 Similarly, for the \c previous() function, we obtain an iterator for
485 \c contacts and then:
488 \li If the iterator is at the end of \c contacts, we clear the
490 \li If the iterator is at the beginning of \c contacts, we move it to
492 \li We then decrement the iterator by one.
495 \snippet tutorials/addressbook/part3/addressbook.cpp previous() function
497 Again, we display the contents of the current object in \c contacts.
502 \page tutorials-addressbook-part4.html
504 \example tutorials/addressbook/part4
505 \title Part 4 - Editing and Removing Addresses
507 Now we look at ways to modify the contents of contacts stored in
510 \image addressbook-tutorial-screenshot.png
512 We now have an address book that not only holds contacts in an
513 organized manner, but also allows navigation. It would be
514 convenient to include edit and remove functions so that a
515 contact's details can be changed when needed. However, this
516 requires a little improvement, in the form of enums. We defined
517 two modes: \c{AddingMode} and \c{NavigationMode}, but they were
518 not defined as enum values. Instead, we enabled and disabled the
519 corresponding buttons manually, resulting in multiple lines of
522 Here we define the \c Mode enum with three different values:
525 \li \c{NavigationMode},
526 \li \c{AddingMode}, and
530 \section1 Defining the AddressBook Class
532 The \c addressbook.h file is updated to contain the \c Mode enum:
534 \snippet tutorials/addressbook/part4/addressbook.h Mode enum
536 We also add two new slots, \c editContact() and \c removeContact(), to
537 our current list of public slots.
539 \snippet tutorials/addressbook/part4/addressbook.h edit and remove slots
541 In order to switch between modes, we introduce the \c updateInterface() function
542 to control the enabling and disabling of all QPushButton objects. We also
543 add two new push buttons, \c editButton and \c removeButton, for the edit
544 and remove functions mentioned earlier.
546 \snippet tutorials/addressbook/part4/addressbook.h updateInterface() declaration
548 \snippet tutorials/addressbook/part4/addressbook.h buttons declaration
550 \snippet tutorials/addressbook/part4/addressbook.h mode declaration
552 Lastly, we declare \c currentMode to keep track of the enum's current mode.
554 \section1 Implementing the AddressBook Class
556 We now implement the mode-changing features of the address
557 book. The \c editButton and \c removeButton are instantiated and
558 disabled by default. The address book starts with zero contacts
561 \snippet tutorials/addressbook/part4/addressbook.cpp edit and remove buttons
563 These buttons are then connected to their respective slots, \c editContact()
564 and \c removeContact(), and we add them to \c buttonLayout1.
566 \snippet tutorials/addressbook/part4/addressbook.cpp connecting edit and remove
568 \snippet tutorials/addressbook/part4/addressbook.cpp adding edit and remove to the layout
570 The \c editContact() function stores the contact's old details in
571 \c oldName and \c oldAddress, before switching the mode to \c EditingMode.
572 In this mode, the \c submitButton and \c cancelButton are both enabled,
573 hence, the user can change the contact's details and click either button.
575 \snippet tutorials/addressbook/part4/addressbook.cpp editContact() function
577 The \c submitContact() function has been divided in two with an \c{if-else}
578 statement. We check \c currentMode to see if it's in \c AddingMode. If it is,
579 we proceed with our adding process.
581 \snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function beginning
583 \snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function part1
585 Otherwise, we check to see if \c currentMode is in \c EditingMode. If it
586 is, we compare \c oldName with \c name. If the name has changed, we remove
587 the old contact from \c contacts and insert the newly updated contact.
589 \snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function part2
591 If only the address has changed (i.e., \c oldAddress is not the same as \c address),
592 we update the contact's address. Lastly, we set \c currentMode to
593 \c NavigationMode. This is an important step as it re-enables all the
594 disabled push buttons.
596 To remove a contact from the address book, we implement the
597 \c removeContact() function. This function checks to see if the contact
598 exists in \c contacts.
600 \snippet tutorials/addressbook/part4/addressbook.cpp removeContact() function
602 If it does, we display a QMessageBox, to confirm the removal with the
603 user. Once the user has confirmed, we call \c previous() to ensure that the
604 user interface shows another contact, and we remove the contact using \l{QMap}'s
605 \l{QMap::remove()}{remove()} function. As a courtesy, we display a QMessageBox
606 to inform the user. Both the message boxes used in this function are shown below:
608 \image addressbook-tutorial-part4-remove.png
610 \section2 Updating the User Interface
612 We mentioned the \c updateInterface() function earlier as a means to
613 enable and disable the push buttons depending on the current mode.
614 The function updates the current mode according to the \c mode argument
615 passed to it, assigning it to \c currentMode before checking its value.
617 Each of the push buttons is then enabled or disabled, depending on the
618 current mode. The code for \c AddingMode and \c EditingMode is shown below:
620 \snippet tutorials/addressbook/part4/addressbook.cpp update interface() part 1
622 For \c NavigationMode, however, we include conditions within the parameters
623 of the QPushButton::setEnabled() function. This is to ensure that
624 \c editButton and \c removeButton are enabled when there is at least one
625 contact in the address book; \c nextButton and \c previousButton are only
626 enabled when there is more than one contact in the address book.
628 \snippet tutorials/addressbook/part4/addressbook.cpp update interface() part 2
630 By setting the mode and updating the user interface in the same
631 function, we avoid the possibility of the user interface getting
632 out of sync with the internal state of the application.
636 \page tutorials-addressbook-part5.html
638 \example tutorials/addressbook/part5
639 \title Part 5 - Adding a Find Function
641 Here we look at ways to locate contacts and addresses in the
644 \image addressbook-tutorial-part5-screenshot.png
646 As we add contacts to our address book, it becomes tedious to
647 navigate the list with the \e Next and \e Previous buttons. A \e
648 Find function would be more efficient. The screenshot above shows
649 the \e Find button and its position on the panel of buttons.
651 When the user clicks on the \e Find button, it is useful to
652 display a dialog that prompts for a contact's name. Qt provides
653 QDialog, which we subclass here to implement a \c FindDialog
656 \section1 Defining the FindDialog Class
658 \image addressbook-tutorial-part5-finddialog.png
660 In order to subclass QDialog, we first include the header for QDialog in
661 the \c finddialog.h file. Also, we use forward declaration to declare
662 QLineEdit and QPushButton since we will be using those widgets in our
665 As in our \c AddressBook class, the \c FindDialog class includes
666 the Q_OBJECT macro and its constructor is defined to accept a parent
667 QWidget, even though the dialog will be opened as a separate window.
669 \snippet tutorials/addressbook/part5/finddialog.h FindDialog header
671 We define a public function, \c getFindText(), to be used by classes that
672 instantiate \c FindDialog. This function allows these classes to obtain the
673 search string entered by the user. A public slot, \c findClicked(), is also
674 defined to handle the search string when the user clicks the \uicontrol Find
677 Lastly, we define the private variables, \c findButton, \c lineEdit
678 and \c findText, corresponding to the \uicontrol Find button, the line edit
679 into which the user types the search string, and an internal string
680 used to store the search string for later use.
682 \section1 Implementing the FindDialog Class
684 Within the constructor of \c FindDialog, we set up the private variables,
685 \c lineEdit, \c findButton and \c findText. We use a QHBoxLayout to
686 position the widgets.
688 \snippet tutorials/addressbook/part5/finddialog.cpp constructor
690 We set the layout and window title, as well as connect the signals to their
691 respective slots. Notice that \c{findButton}'s \l{QPushButton::clicked()}
692 {clicked()} signal is connected to to \c findClicked() and
693 \l{QDialog::accept()}{accept()}. The \l{QDialog::accept()}{accept()} slot
694 provided by QDialog hides the dialog and sets the result code to
695 \l{QDialog::}{Accepted}. We use this function to help \c{AddressBook}'s
696 \c findContact() function know when the \c FindDialog object has been
697 closed. We will explain this logic in further detail when discussing the
698 \c findContact() function.
700 \image addressbook-tutorial-part5-signals-and-slots.png
702 In \c findClicked(), we validate \c lineEdit to ensure that the user
703 did not click the \uicontrol Find button without entering a contact's name. Then, we set
704 \c findText to the search string, extracted from \c lineEdit. After that,
705 we clear the contents of \c lineEdit and hide the dialog.
707 \snippet tutorials/addressbook/part5/finddialog.cpp findClicked() function
709 The \c findText variable has a public getter function, \c getFindText(),
710 associated with it. Since we only ever set \c findText directly in both the
711 constructor and in the \c findClicked() function, we do not create a
712 setter function to accompany \c getFindText().
713 Because \c getFindText() is public, classes instantiating and using
714 \c FindDialog can always access the search string that the user has
715 entered and accepted.
717 \snippet tutorials/addressbook/part5/finddialog.cpp getFindText() function
719 \section1 Defining the AddressBook Class
721 To ensure we can use \c FindDialog from within our \c AddressBook class, we
722 include \c finddialog.h in the \c addressbook.h file.
724 \snippet tutorials/addressbook/part5/addressbook.h include finddialog's header
726 So far, all our address book features have a QPushButton and a
727 corresponding slot. Similarly, for the \uicontrol Find feature we have
728 \c findButton and \c findContact().
730 The \c findButton is declared as a private variable and the
731 \c findContact() function is declared as a public slot.
733 \snippet tutorials/addressbook/part5/addressbook.h findContact() declaration
735 \snippet tutorials/addressbook/part5/addressbook.h findButton declaration
737 Lastly, we declare the private variable, \c dialog, which we will use to
738 refer to an instance of \c FindDialog.
740 \snippet tutorials/addressbook/part5/addressbook.h FindDialog declaration
742 Once we have instantiated a dialog, we will want to use it more than once;
743 using a private variable allows us to refer to it from more than one place
746 \section1 Implementing the AddressBook Class
748 Within the \c AddressBook class's constructor, we instantiate our private
749 objects, \c findButton and \c findDialog:
751 \snippet tutorials/addressbook/part5/addressbook.cpp instantiating findButton
753 \snippet tutorials/addressbook/part5/addressbook.cpp instantiating FindDialog
755 Next, we connect the \c{findButton}'s
756 \l{QPushButton::clicked()}{clicked()} signal to \c findContact().
758 \snippet tutorials/addressbook/part5/addressbook.cpp signals and slots for find
760 Now all that is left is the code for our \c findContact() function:
762 \snippet tutorials/addressbook/part5/addressbook.cpp findContact() function
764 We start out by displaying the \c FindDialog instance, \c dialog. This is
765 when the user enters a contact name to look up. Once the user clicks
766 the dialog's \c findButton, the dialog is hidden and the result code is
767 set to QDialog::Accepted. This ensures that
768 our \c if statement is always true.
770 We then proceed to extract the search string, which in this case is
771 \c contactName, using \c{FindDialog}'s \c getFindText() function. If the
772 contact exists in our address book, we display it immediately. Otherwise,
773 we display the QMessageBox shown below to indicate that their search
776 \image addressbook-tutorial-part5-notfound.png
780 \page tutorials-addressbook-part6.html
782 \example tutorials/addressbook/part6
783 \title Part 6 - Loading and Saving
785 This part covers the Qt file handling features we use to write
786 loading and saving routines for the address book.
788 \image addressbook-tutorial-part6-screenshot.png
790 Although browsing and searching the contact list are useful
791 features, our address book is not complete until we can save
792 existing contacts and load them again at a later time.
794 Qt provides a number of classes for \l{Input/Output and Networking}
795 {input and output}, but we have chosen to use two which are simple to use
796 in combination: QFile and QDataStream.
798 A QFile object represents a file on disk that can be read from and written
799 to. QFile is a subclass of the more general QIODevice class which
800 represents many different kinds of devices.
802 A QDataStream object is used to serialize binary data so that it can be
803 stored in a QIODevice and retrieved again later. Reading from a QIODevice
804 and writing to it is as simple as opening the stream - with the respective
805 device as a parameter - and reading from or writing to it.
808 \section1 Defining the AddressBook Class
810 We declare two public slots, \c saveToFile() and \c loadFromFile(), as well
811 as two QPushButton objects, \c loadButton and \c saveButton.
813 \snippet tutorials/addressbook/part6/addressbook.h save and load functions declaration
815 \snippet tutorials/addressbook/part6/addressbook.h save and load buttons declaration
817 \section1 Implementing the AddressBook Class
819 In our constructor, we instantiate \c loadButton and \c saveButton.
820 Ideally, it would be more user-friendly to set the push buttons' labels
821 to "Load contacts from a file" and "Save contacts to a file". However, due
822 to the size of our other push buttons, we set the labels to \uicontrol{Load...}
823 and \uicontrol{Save...}. Fortunately, Qt provides a simple way to set tooltips with
824 \l{QWidget::setToolTip()}{setToolTip()} and we use it in the following way
825 for our push buttons:
827 \snippet tutorials/addressbook/part6/addressbook.cpp tooltip 1
829 \snippet tutorials/addressbook/part6/addressbook.cpp tooltip 2
831 Although it is not shown here, just like the other features we implemented,
832 we add the push buttons to the layout panel on the right, \c buttonLayout1,
833 and we connect the push buttons' \l{QPushButton::clicked()}{clicked()}
834 signals to their respective slots.
836 For the saving feature, we first obtain \c fileName using
837 QFileDialog::getSaveFileName(). This is a convenience function provided
838 by QFileDialog, which pops up a modal file dialog and allows the user to
839 enter a file name or select any existing \c{.abk} file. The \c{.abk} file
840 is our Address Book extension that we create when we save contacts.
842 \snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part1
844 The file dialog that pops up is displayed in the screenshot below:
846 \image addressbook-tutorial-part6-save.png
848 If \c fileName is not empty, we create a QFile object, \c file, with
849 \c fileName. QFile works with QDataStream as QFile is a QIODevice.
851 Next, we attempt to open the file in \l{QIODevice::}{WriteOnly} mode.
852 If this is unsuccessful, we display a QMessageBox to inform the user.
854 \snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part2
856 Otherwise, we instantiate a QDataStream object, \c out, to write the open
857 file. QDataStream requires that the same version of the stream is used
858 for reading and writing. We ensure that this is the case by setting the
859 version used to the \l{QDataStream::Qt_4_5}{version introduced with Qt 4.5}
860 before serializing the data to \c file.
862 \snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part3
864 For the loading feature, we also obtain \c fileName using
865 QFileDialog::getOpenFileName(). This function, the counterpart to
866 QFileDialog::getSaveFileName(), also pops up the modal file dialog and
867 allows the user to enter a file name or select any existing \c{.abk} file
868 to load it into the address book.
870 \snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part1
872 On Windows, for example, this function pops up a native file dialog, as
873 shown in the following screenshot.
875 \image addressbook-tutorial-part6-load.png
877 If \c fileName is not empty, again, we use a QFile object, \c file, and
878 attempt to open it in \l{QIODevice::}{ReadOnly} mode. Similar to our
879 implementation of \c saveToFile(), if this attempt is unsuccessful, we
880 display a QMessageBox to inform the user.
882 \snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part2
884 Otherwise, we instantiate a QDataStream object, \c in, set its version as
885 above and read the serialized data into the \c contacts data structure.
886 The \c contacts object is emptied before data is read into it to simplify
887 the file reading process. A more advanced method would be to read the
888 contacts into a temporary QMap object, and copy over non-duplicate contacts
891 \snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part3
893 To display the contacts that have been read from the file, we must first
894 validate the data obtained to ensure that the file we read from actually
895 contains address book contacts. If it does, we display the first contact;
896 otherwise, we display a QMessageBox to inform the user about the problem.
897 Lastly, we update the interface to enable and disable the push buttons
902 \page tutorials-addressbook-part7.html
904 \example tutorials/addressbook/part7
905 \title Part 7 - Additional Features
907 This part covers some additional features that make the address
908 book more convenient for the frequent user.
910 \image addressbook-tutorial-part7-screenshot.png
912 Although our address book is useful in isolation, it would be
913 better if we could exchange contact data with other applications.
914 The vCard format is a popular file format that can be used for
915 this purpose. Here we extend our address book client to allow
916 contacts to be exported to vCard \c{.vcf} files.
918 \section1 Defining the AddressBook Class
920 We add a QPushButton object, \c exportButton, and a corresponding public
921 slot, \c exportAsVCard() to our \c AddressBook class in the
922 \c addressbook.h file.
924 \snippet tutorials/addressbook/part7/addressbook.h exportAsVCard() declaration
926 \snippet tutorials/addressbook/part7/addressbook.h exportButton declaration
928 \section1 Implementing the AddressBook Class
930 Within the \c AddressBook constructor, we connect \c{exportButton}'s
931 \l{QPushButton::clicked()}{clicked()} signal to \c exportAsVCard().
932 We also add this button to our \c buttonLayout1, the layout responsible
933 for our panel of buttons on the right.
935 In our \c exportAsVCard() function, we start by extracting the contact's
936 name into \c name. We declare \c firstName, \c lastName and \c nameList.
937 Next, we look for the index of the first white space in \c name. If there
938 is a white space, we split the contact's name into \c firstName and
939 \c lastName. Then, we replace the space with an underscore ("_").
940 Alternately, if there is no white space, we assume that the contact only
943 \snippet tutorials/addressbook/part7/addressbook.cpp export function part1
945 As with the \c saveToFile() function, we open a file dialog to let the user
946 choose a location for the file. Using the file name chosen, we create an
947 instance of QFile to write to.
949 We attempt to open the file in \l{QIODevice::}{WriteOnly} mode. If this
950 process fails, we display a QMessageBox to inform the user about the
951 problem and return. Otherwise, we pass the file as a parameter to a
952 QTextStream object, \c out. Like QDataStream, the QTextStream class
953 provides functionality to read and write plain text to files. As a result,
954 the \c{.vcf} file generated can be opened for editing in a text editor.
956 \snippet tutorials/addressbook/part7/addressbook.cpp export function part2
958 We then write out a vCard file with the \c{BEGIN:VCARD} tag, followed by
959 the \c{VERSION:2.1} tag. The contact's name is written with the \c{N:}
960 tag. For the \c{FN:} tag, which fills in the "File as" property of a vCard,
961 we have to check whether the contact has a last name or not. If the contact
962 does, we use the details in \c nameList to fill it. Otherwise, we write
965 \snippet tutorials/addressbook/part7/addressbook.cpp export function part3
967 We proceed to write the contact's address. The semicolons in the address
968 are escaped with "\\", the newlines are replaced with semicolons, and the
969 commas are replaced with spaces. Lastly, we write the \c{ADR;HOME:;}
970 tag, followed by \c address and then the \c{END:VCARD} tag.
972 \snippet tutorials/addressbook/part7/addressbook.cpp export function part4
974 In the end, a QMessageBox is displayed to inform the user that the vCard
975 has been successfully exported.
977 \e{vCard is a trademark of the \l{http://www.imc.org}
978 {Internet Mail Consortium}}.