1 | /****************************************************************************
|
---|
2 | **
|
---|
3 | ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
---|
4 | ** All rights reserved.
|
---|
5 | ** Contact: Nokia Corporation ([email protected])
|
---|
6 | **
|
---|
7 | ** This file is part of the documentation of the Qt Toolkit.
|
---|
8 | **
|
---|
9 | ** $QT_BEGIN_LICENSE:FDL$
|
---|
10 | ** Commercial Usage
|
---|
11 | ** Licensees holding valid Qt Commercial licenses may use this file in
|
---|
12 | ** accordance with the Qt Commercial License Agreement provided with the
|
---|
13 | ** Software or, alternatively, in accordance with the terms contained in a
|
---|
14 | ** written agreement between you and Nokia.
|
---|
15 | **
|
---|
16 | ** GNU Free Documentation License
|
---|
17 | ** Alternatively, this file may be used under the terms of the GNU Free
|
---|
18 | ** Documentation License version 1.3 as published by the Free Software
|
---|
19 | ** Foundation and appearing in the file included in the packaging of this
|
---|
20 | ** file.
|
---|
21 | **
|
---|
22 | ** If you have questions regarding the use of this file, please contact
|
---|
23 | ** Nokia at [email protected].
|
---|
24 | ** $QT_END_LICENSE$
|
---|
25 | **
|
---|
26 | ****************************************************************************/
|
---|
27 |
|
---|
28 | /*!
|
---|
29 | \page tutorials-addressbook.html
|
---|
30 |
|
---|
31 | \title Address Book Tutorial
|
---|
32 | \brief An introduction to GUI programming, showing how to put together a
|
---|
33 | simple yet fully-functioning application.
|
---|
34 |
|
---|
35 | This tutorial is an introduction to GUI programming with the Qt
|
---|
36 | cross-platform framework.
|
---|
37 |
|
---|
38 | \image addressbook-tutorial-screenshot.png
|
---|
39 |
|
---|
40 | \omit
|
---|
41 | It doesn't cover everything; the emphasis is on teaching the programming
|
---|
42 | philosophy of GUI programming, and Qt's features are introduced as needed.
|
---|
43 | Some commonly used features are never used in this tutorial.
|
---|
44 | \endomit
|
---|
45 |
|
---|
46 | In this tutorial, you will learn about some of the basic
|
---|
47 | components of Qt, including:
|
---|
48 |
|
---|
49 | \list
|
---|
50 | \o Widgets and layout managers
|
---|
51 | \o Container classes
|
---|
52 | \o Signals and slots
|
---|
53 | \o Input and output devices
|
---|
54 | \endlist
|
---|
55 |
|
---|
56 | If you are new to Qt, we recommend reading \l{How to Learn Qt} first.
|
---|
57 |
|
---|
58 | Tutorial contents:
|
---|
59 |
|
---|
60 | \list 1
|
---|
61 | \o \l{tutorials/addressbook/part1}{Designing the User Interface}
|
---|
62 | \o \l{tutorials/addressbook/part2}{Adding Addresses}
|
---|
63 | \o \l{tutorials/addressbook/part3}{Navigating between Entries}
|
---|
64 | \o \l{tutorials/addressbook/part4}{Editing and Removing Addresses}
|
---|
65 | \o \l{tutorials/addressbook/part5}{Adding a Find Function}
|
---|
66 | \o \l{tutorials/addressbook/part6}{Loading and Saving}
|
---|
67 | \o \l{tutorials/addressbook/part7}{Additional Features}
|
---|
68 | \endlist
|
---|
69 |
|
---|
70 | The tutorial source code is located in \c{examples/tutorials/addressbook}.
|
---|
71 |
|
---|
72 | Although this little application does not look much like a
|
---|
73 | fully-fledged modern GUI application, it uses many of the basic
|
---|
74 | elements that are used in more complex applications. After you
|
---|
75 | have worked through this tutorial, we recommend reading the
|
---|
76 | \l{mainwindows/application}{Application} example, which presents a
|
---|
77 | small GUI application, with menus, toolbars, a status bar, and so
|
---|
78 | on.
|
---|
79 | */
|
---|
80 |
|
---|
81 | /*!
|
---|
82 | \page tutorials-addressbook-part1.html
|
---|
83 |
|
---|
84 | \example tutorials/addressbook/part1
|
---|
85 | \title Part 1 - Designing the User Interface
|
---|
86 |
|
---|
87 | This first part covers the design of the basic graphical user
|
---|
88 | interface (GUI) for our address book application.
|
---|
89 |
|
---|
90 | The first step in creating a GUI program is to design the user
|
---|
91 | interface. Here the our goal is to set up the labels and input
|
---|
92 | fields to implement a basic address book. The figure below is a
|
---|
93 | screenshot of the expected output.
|
---|
94 |
|
---|
95 | \image addressbook-tutorial-part1-screenshot.png
|
---|
96 |
|
---|
97 | We require two QLabel objects, \c nameLabel and \c addressLabel, as well
|
---|
98 | as two input fields, a QLineEdit object, \c nameLine, and a QTextEdit
|
---|
99 | object, \c addressText, to enable the user to enter a contact's name and
|
---|
100 | address. The widgets used and their positions are shown in the figure
|
---|
101 | below.
|
---|
102 |
|
---|
103 | \image addressbook-tutorial-part1-labeled-screenshot.png
|
---|
104 |
|
---|
105 | There are three files used to implement this address book:
|
---|
106 |
|
---|
107 | \list
|
---|
108 | \o \c{addressbook.h} - the definition file for the \c AddressBook
|
---|
109 | class,
|
---|
110 | \o \c{addressbook.cpp} - the implementation file for the
|
---|
111 | \c AddressBook class, and
|
---|
112 | \o \c{main.cpp} - the file containing a \c main() function, with
|
---|
113 | an instance of \c AddressBook.
|
---|
114 | \endlist
|
---|
115 |
|
---|
116 | \section1 Qt Programming - Subclassing
|
---|
117 |
|
---|
118 | When writing Qt programs, we usually subclass Qt objects to add
|
---|
119 | functionality. This is one of the essential concepts behind creating
|
---|
120 | custom widgets or collections of standard widgets. Subclassing to
|
---|
121 | extend or change the behavior of a widget has the following advantages:
|
---|
122 |
|
---|
123 | \list
|
---|
124 | \o We can write implementations of virtual or pure virtual functions to
|
---|
125 | obtain exactly what we need, falling back on the base class's implementation
|
---|
126 | when necessary.
|
---|
127 | \o It allows us to encapsulate parts of the user interface within a class,
|
---|
128 | so that the other parts of the application don't need to know about the
|
---|
129 | individual widgets in the user interface.
|
---|
130 | \o The subclass can be used to create multiple custom widgets in the same
|
---|
131 | application or library, and the code for the subclass can be reused in other
|
---|
132 | projects.
|
---|
133 | \endlist
|
---|
134 |
|
---|
135 | Since Qt does not provide a specific address book widget, we subclass a
|
---|
136 | standard Qt widget class and add features to it. The \c AddressBook class
|
---|
137 | we create in this tutorial can be reused in situations where a basic address
|
---|
138 | book widget is needed.
|
---|
139 |
|
---|
140 | \section1 Defining the AddressBook Class
|
---|
141 |
|
---|
142 | The \l{tutorials/addressbook/part1/addressbook.h}{\c addressbook.h} file is
|
---|
143 | used to define the \c AddressBook class.
|
---|
144 |
|
---|
145 | We start by defining \c AddressBook as a QWidget subclass and declaring
|
---|
146 | a constructor. We also use the Q_OBJECT macro to indicate that the class
|
---|
147 | uses internationalization and Qt's signals and slots features, even
|
---|
148 | if we do not use all of these features at this stage.
|
---|
149 |
|
---|
150 | \snippet tutorials/addressbook/part1/addressbook.h class definition
|
---|
151 |
|
---|
152 | The class holds declarations of \c nameLine and \c addressText,
|
---|
153 | the private instances of QLineEdit and QTextEdit mentioned
|
---|
154 | earlier. The data stored in \c nameLine and \c addressText will
|
---|
155 | be needed for many of the address book functions.
|
---|
156 |
|
---|
157 | We don't include declarations of the QLabel objects we will use
|
---|
158 | because we will not need to reference them once they have been
|
---|
159 | created. The way Qt tracks the ownership of objects is explained
|
---|
160 | in the next section.
|
---|
161 |
|
---|
162 | The Q_OBJECT macro itself implements some of the more advanced features of Qt.
|
---|
163 | For now, it is useful to think of the Q_OBJECT macro as a shortcut which allows
|
---|
164 | us to use the \l{QObject::}{tr()} and \l{QObject::}{connect()} functions.
|
---|
165 |
|
---|
166 | We have now completed the \c addressbook.h file and we move on to
|
---|
167 | implement the corresponding \c addressbook.cpp file.
|
---|
168 |
|
---|
169 | \section1 Implementing the AddressBook Class
|
---|
170 |
|
---|
171 | The constructor of \c AddressBook accepts a QWidget parameter, \a parent.
|
---|
172 | By convention, we pass this parameter to the base class's constructor.
|
---|
173 | This concept of ownership, where a parent can have one or more children,
|
---|
174 | is useful for grouping widgets in Qt. For example, if you delete a parent,
|
---|
175 | all of its children will be deleted as well.
|
---|
176 |
|
---|
177 | \snippet tutorials/addressbook/part1/addressbook.cpp constructor and input fields
|
---|
178 |
|
---|
179 | In this constructor, the QLabel objects \c nameLabel and \c
|
---|
180 | addressLabel are instantiated, as well as \c nameLine and \c
|
---|
181 | addressText. The \l{QObject::tr()}{tr()} function returns a
|
---|
182 | translated version of the string, if there is one
|
---|
183 | available. Otherwise it returns the string itself. This function
|
---|
184 | marks its QString parameter as one that should be translated into
|
---|
185 | other languages. It should be used wherever a translatable string
|
---|
186 | appears.
|
---|
187 |
|
---|
188 | When programming with Qt, it is useful to know how layouts work.
|
---|
189 | Qt provides three main layout classes: QHBoxLayout, QVBoxLayout
|
---|
190 | and QGridLayout to handle the positioning of widgets.
|
---|
191 |
|
---|
192 | \image addressbook-tutorial-part1-labeled-layout.png
|
---|
193 |
|
---|
194 | We use a QGridLayout to position our labels and input fields in a
|
---|
195 | structured manner. QGridLayout divides the available space into a grid and
|
---|
196 | places widgets in the cells we specify with row and column numbers. The
|
---|
197 | diagram above shows the layout cells and the position of our widgets, and
|
---|
198 | we specify this arrangement using the following code:
|
---|
199 |
|
---|
200 | \snippet tutorials/addressbook/part1/addressbook.cpp layout
|
---|
201 |
|
---|
202 | Notice that \c addressLabel is positioned using Qt::AlignTop as an
|
---|
203 | additional argument. This is to make sure it is not vertically centered in
|
---|
204 | cell (1,0). For a basic overview on Qt Layouts, refer to the
|
---|
205 | \l{Layout Management} documentation.
|
---|
206 |
|
---|
207 | In order to install the layout object onto the widget, we have to invoke
|
---|
208 | the widget's \l{QWidget::setLayout()}{setLayout()} function:
|
---|
209 |
|
---|
210 | \snippet tutorials/addressbook/part1/addressbook.cpp setting the layout
|
---|
211 |
|
---|
212 | Lastly, we set the widget's title to "Simple Address Book".
|
---|
213 |
|
---|
214 | \section1 Running the Application
|
---|
215 |
|
---|
216 | A separate file, \c main.cpp, is used for the \c main() function. Within
|
---|
217 | this function, we instantiate a QApplication object, \c app. QApplication
|
---|
218 | is responsible for various application-wide resources, such as the default
|
---|
219 | font and cursor, and for running an event loop. Hence, there is always one
|
---|
220 | QApplication object in every GUI application using Qt.
|
---|
221 |
|
---|
222 | \snippet tutorials/addressbook/part1/main.cpp main function
|
---|
223 |
|
---|
224 | We construct a new \c AddressBook widget on the stack and invoke
|
---|
225 | its \l{QWidget::show()}{show()} function to display it.
|
---|
226 | However, the widget will not be shown until the application's event loop
|
---|
227 | is started. We start the event loop by calling the application's
|
---|
228 | \l{QApplication::}{exec()} function; the result returned by this function
|
---|
229 | is used as the return value from the \c main() function. At this point,
|
---|
230 | it becomes apparent why we instanciated \c AddressBook on the stack: It
|
---|
231 | will now go out of scope. Therefore, \c AddressBook and all its child widgets
|
---|
232 | will be deleted, thus preventing memory leaks.
|
---|
233 | */
|
---|
234 |
|
---|
235 | /*!
|
---|
236 | \page tutorials-addressbook-part2.html
|
---|
237 |
|
---|
238 | \example tutorials/addressbook/part2
|
---|
239 | \title Part 2 - Adding Addresses
|
---|
240 |
|
---|
241 | The next step in creating the address book is to implement some
|
---|
242 | user interactions.
|
---|
243 |
|
---|
244 | \image addressbook-tutorial-part2-add-contact.png
|
---|
245 |
|
---|
246 | We will provide a push button that the user can click to add a new contact.
|
---|
247 | Also, some form of data structure is needed to store these contacts in an
|
---|
248 | organized way.
|
---|
249 |
|
---|
250 | \section1 Defining the AddressBook Class
|
---|
251 |
|
---|
252 | Now that we have the labels and input fields set up, we add push buttons to
|
---|
253 | complete the process of adding a contact. This means that our
|
---|
254 | \c addressbook.h file now has three QPushButton objects declared and three
|
---|
255 | corresponding public slots.
|
---|
256 |
|
---|
257 | \snippet tutorials/addressbook/part2/addressbook.h slots
|
---|
258 |
|
---|
259 | A slot is a function that responds to a particular signal. We will discuss
|
---|
260 | this concept in further detail when implementing the \c AddressBook class.
|
---|
261 | However, for an overview of Qt's signals and slots concept, you can refer
|
---|
262 | to the \l{Signals and Slots} document.
|
---|
263 |
|
---|
264 | Three QPushButton objects (\c addButton, \c submitButton, and
|
---|
265 | \c cancelButton) are now included in our private variable declarations,
|
---|
266 | along with \c nameLine and \c addressText.
|
---|
267 |
|
---|
268 | \snippet tutorials/addressbook/part2/addressbook.h pushbutton declaration
|
---|
269 |
|
---|
270 | We need a container to store our address book contacts, so that we can
|
---|
271 | traverse and display them. A QMap object, \c contacts, is used for this
|
---|
272 | purpose as it holds a key-value pair: the contact's name as the \e key,
|
---|
273 | and the contact's address as the \e{value}.
|
---|
274 |
|
---|
275 | \snippet tutorials/addressbook/part2/addressbook.h remaining private variables
|
---|
276 |
|
---|
277 | We also declare two private QString objects, \c oldName and \c oldAddress.
|
---|
278 | These objects are needed to hold the name and address of the contact that
|
---|
279 | was last displayed, before the user clicked \gui Add. So, when the user clicks
|
---|
280 | \gui Cancel, we can revert to displaying the details of the last contact.
|
---|
281 |
|
---|
282 | \section1 Implementing the AddressBook Class
|
---|
283 |
|
---|
284 | Within the constructor of \c AddressBook, we set the \c nameLine and
|
---|
285 | \c addressText to read-only, so that we can only display but not edit
|
---|
286 | existing contact details.
|
---|
287 |
|
---|
288 | \dots
|
---|
289 | \snippet tutorials/addressbook/part2/addressbook.cpp setting readonly 1
|
---|
290 | \dots
|
---|
291 | \snippet tutorials/addressbook/part2/addressbook.cpp setting readonly 2
|
---|
292 |
|
---|
293 | Then, we instantiate our push buttons: \c addButton, \c submitButton, and
|
---|
294 | \c cancelButton.
|
---|
295 |
|
---|
296 | \snippet tutorials/addressbook/part2/addressbook.cpp pushbutton declaration
|
---|
297 |
|
---|
298 | The \c addButton is displayed by invoking the \l{QPushButton::show()}
|
---|
299 | {show()} function, while the \c submitButton and \c cancelButton are
|
---|
300 | hidden by invoking \l{QPushButton::hide()}{hide()}. These two push
|
---|
301 | buttons will only be displayed when the user clicks \gui Add and this is
|
---|
302 | handled by the \c addContact() function discussed below.
|
---|
303 |
|
---|
304 | \snippet tutorials/addressbook/part2/addressbook.cpp connecting signals and slots
|
---|
305 |
|
---|
306 | We connect the push buttons' \l{QPushButton::clicked()}{clicked()} signal
|
---|
307 | to their respective slots. The figure below illustrates this.
|
---|
308 |
|
---|
309 | \image addressbook-tutorial-part2-signals-and-slots.png
|
---|
310 |
|
---|
311 | Next, we arrange our push buttons neatly to the right of our address book
|
---|
312 | widget, using a QVBoxLayout to line them up vertically.
|
---|
313 |
|
---|
314 | \snippet tutorials/addressbook/part2/addressbook.cpp vertical layout
|
---|
315 |
|
---|
316 | The \l{QBoxLayout::addStretch()}{addStretch()} function is used to ensure
|
---|
317 | the push buttons are not evenly spaced, but arranged closer to the top of
|
---|
318 | the widget. The figure below shows the difference between using
|
---|
319 | \l{QBoxLayout::addStretch()}{addStretch()} and not using it.
|
---|
320 |
|
---|
321 | \image addressbook-tutorial-part2-stretch-effects.png
|
---|
322 |
|
---|
323 | We then add \c buttonLayout1 to \c mainLayout, using
|
---|
324 | \l{QGridLayout::addLayout()}{addLayout()}. This gives us nested layouts
|
---|
325 | as \c buttonLayout1 is now a child of \c mainLayout.
|
---|
326 |
|
---|
327 | \snippet tutorials/addressbook/part2/addressbook.cpp grid layout
|
---|
328 |
|
---|
329 | Our layout coordinates now look like this:
|
---|
330 |
|
---|
331 | \image addressbook-tutorial-part2-labeled-layout.png
|
---|
332 |
|
---|
333 | In the \c addContact() function, we store the last displayed contact
|
---|
334 | details in \c oldName and \c oldAddress. Then we clear these input
|
---|
335 | fields and turn off the read-only mode. The focus is set on \c nameLine
|
---|
336 | and we display \c submitButton and \c cancelButton.
|
---|
337 |
|
---|
338 | \snippet tutorials/addressbook/part2/addressbook.cpp addContact
|
---|
339 |
|
---|
340 | The \c submitContact() function can be divided into three parts:
|
---|
341 |
|
---|
342 | \list 1
|
---|
343 | \o We extract the contact's details from \c nameLine and \c addressText
|
---|
344 | and store them in QString objects. We also validate to make sure that the
|
---|
345 | user did not click \gui Submit with empty input fields; otherwise, a
|
---|
346 | QMessageBox is displayed to remind the user for a name and address.
|
---|
347 |
|
---|
348 | \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part1
|
---|
349 |
|
---|
350 | \o We then proceed to check if the contact already exists. If it does not
|
---|
351 | exist, we add the contact to \c contacts and we display a QMessageBox to
|
---|
352 | inform the user that the contact has been added.
|
---|
353 |
|
---|
354 | \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part2
|
---|
355 |
|
---|
356 | If the contact already exists, again, we display a QMessageBox to inform
|
---|
357 | the user about this, preventing the user from adding duplicate contacts.
|
---|
358 | Our \c contacts object is based on key-value pairs of name and address,
|
---|
359 | hence, we want to ensure that \e key is unique.
|
---|
360 |
|
---|
361 | \o Once we have handled both cases mentioned above, we restore the push
|
---|
362 | buttons to their normal state with the following code:
|
---|
363 |
|
---|
364 | \snippet tutorials/addressbook/part2/addressbook.cpp submitContact part3
|
---|
365 |
|
---|
366 | \endlist
|
---|
367 |
|
---|
368 | The screenshot below shows the QMessageBox object we use to display
|
---|
369 | information messages to the user.
|
---|
370 |
|
---|
371 | \image addressbook-tutorial-part2-add-successful.png
|
---|
372 |
|
---|
373 | The \c cancel() function restores the last displayed contact details and
|
---|
374 | enables \c addButton, as well as hides \c submitButton and
|
---|
375 | \c cancelButton.
|
---|
376 |
|
---|
377 | \snippet tutorials/addressbook/part2/addressbook.cpp cancel
|
---|
378 |
|
---|
379 | The general idea behind adding a contact is to give the user the
|
---|
380 | flexibility to click \gui Submit or \gui Cancel at any time. The flowchart below
|
---|
381 | further explains this concept:
|
---|
382 |
|
---|
383 | \image addressbook-tutorial-part2-add-flowchart.png
|
---|
384 | */
|
---|
385 |
|
---|
386 | /*!
|
---|
387 | \page tutorials-addressbook-part3.html
|
---|
388 |
|
---|
389 | \example tutorials/addressbook/part3
|
---|
390 | \title Part 3 - Navigating between Entries
|
---|
391 |
|
---|
392 | The address book is now about half complete. We should add the
|
---|
393 | capability to navigate among the contacts, but first we must
|
---|
394 | decide what sort of a data structure we need for containing these
|
---|
395 | contacts.
|
---|
396 |
|
---|
397 | In the previous section, we used a QMap of key-value pairs with
|
---|
398 | the contact's name as the \e key, and the contact's address as the
|
---|
399 | \e value. This works well for our case. However, in order to
|
---|
400 | navigate and display each entry, a little bit of enhancement is
|
---|
401 | needed.
|
---|
402 |
|
---|
403 | We enhance the QMap by making it replicate a data structure similar to a
|
---|
404 | circularly-linked list, where all elements are connected, including the
|
---|
405 | first element and the last element. The figure below illustrates this data
|
---|
406 | structure.
|
---|
407 |
|
---|
408 | \image addressbook-tutorial-part3-linkedlist.png
|
---|
409 |
|
---|
410 | \section1 Defining the AddressBook Class
|
---|
411 |
|
---|
412 | To add navigation functions to the address book, we must add two
|
---|
413 | more slots to the \c AddressBook class: \c next() and \c
|
---|
414 | previous() to the \c addressbook.h file:
|
---|
415 |
|
---|
416 | \snippet tutorials/addressbook/part3/addressbook.h navigation functions
|
---|
417 |
|
---|
418 | We also require another two QPushButton objects, so we declare \c nextButton
|
---|
419 | and \c previousButton as private variables:
|
---|
420 |
|
---|
421 | \snippet tutorials/addressbook/part3/addressbook.h navigation pushbuttons
|
---|
422 |
|
---|
423 | \section1 Implementing the AddressBook Class
|
---|
424 |
|
---|
|
---|