6.5.3 clean

This commit is contained in:
kleuter
2023-11-01 18:02:52 +01:00
parent bbe896803b
commit 7018d9e6c8
2170 changed files with 57471 additions and 43550 deletions

View File

@ -0,0 +1,10 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
qt_internal_add_example(part1)
qt_internal_add_example(part2)
qt_internal_add_example(part3)
qt_internal_add_example(part4)
qt_internal_add_example(part5)
qt_internal_add_example(part6)
qt_internal_add_example(part7)

View File

@ -0,0 +1,40 @@
The Address Book Tutorial shows how to put together a simple yet
fully-functioning GUI application. The tutorial chapters can be found in the
Qt documentation, which can be viewed using Qt Assistant or a Web browser.
The tutorial is also available online at
http://qt-project.org/doc/qt-5.0/qtwidgets/tutorials-addressbook.html
All programs corresponding to the chapters in the tutorial should
automatically be built when Qt is compiled, or will be provided as
pre-built executables if you have obtained a binary package of Qt.
If you have only compiled the Qt libraries, use the following instructions
to build the tutorial.
On Linux/Unix:
Typing 'make' in this directory builds all the programs (part1/part1,
part2/part2, part3/part3 and so on). Typing 'make' in each subdirectory
builds just that tutorial program.
On Windows:
Create a single Visual Studio project for the tutorial directory in
the usual way. You can do this by typing the following at the command
line:
qmake -tp vc
You should now be able to open the project file in Visual Studio and
build all of the tutorial programs at the same time.
On Mac OS X:
Create an Xcode project with the .pro file in the tutorial directory.
You can do this by typing the following at the command line:
qmake -spec macx-xcode
Then open the generated Xcode project in Xcode and build it.

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -0,0 +1,948 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page tutorials-addressbook.html
\title Address Book Tutorial
\ingroup examples-layout
\brief An introduction to GUI programming, showing how to put together a
simple yet fully-functioning application.
This tutorial is an introduction to GUI programming with the Qt
cross-platform framework.
\image addressbook-tutorial-screenshot.png
\omit
It doesn't cover everything; the emphasis is on teaching the programming
philosophy of GUI programming, and Qt's features are introduced as needed.
Some commonly used features are never used in this tutorial.
\endomit
In this tutorial, you will learn about some of the basic
components of Qt, including:
\list
\li Widgets and layout managers
\li Container classes
\li Signals and slots
\li Input and output devices
\endlist
Tutorial contents:
\list 1
\li \l{tutorials/addressbook/part1}{Designing the User Interface}
\li \l{tutorials/addressbook/part2}{Adding Addresses}
\li \l{tutorials/addressbook/part3}{Navigating between Entries}
\li \l{tutorials/addressbook/part4}{Editing and Removing Addresses}
\li \l{tutorials/addressbook/part5}{Adding a Find Function}
\li \l{tutorials/addressbook/part6}{Loading and Saving}
\li \l{tutorials/addressbook/part7}{Additional Features}
\endlist
The tutorial source code is located in \c{tutorials/addressbook}.
Although this little application does not look much like a
fully-fledged modern GUI application, it uses many of the basic
elements that are used in more complex applications. After you
have worked through this tutorial, we recommend reading the
\l{mainwindows/application}{Application} example, which presents a
small GUI application, with menus, toolbars, a status bar, and so
on.
*/
/*!
\example tutorials/addressbook/part1
\title Part 1 - Designing the User Interface
\brief Describes how to code the user interface of the Address Book Example.
This first part covers the design of the basic graphical user
interface (GUI) for our address book application.
The first step in creating a GUI program is to design the user
interface. Here the our goal is to set up the labels and input
fields to implement a basic address book. The figure below is a
screenshot of the expected output.
\image addressbook-tutorial-part1-screenshot.png
We require two QLabel objects, \c nameLabel and \c addressLabel, as well
as two input fields, a QLineEdit object, \c nameLine, and a QTextEdit
object, \c addressText, to enable the user to enter a contact's name and
address. The widgets used and their positions are shown in the figure
below.
\image addressbook-tutorial-part1-labeled-screenshot.png
There are three files used to implement this address book:
\list
\li \c{addressbook.h} - the definition file for the \c AddressBook
class,
\li \c{addressbook.cpp} - the implementation file for the
\c AddressBook class, and
\li \c{main.cpp} - the file containing a \c main() function, with
an instance of \c AddressBook.
\endlist
\section1 Qt Programming - Subclassing
When writing Qt programs, we usually subclass Qt objects to add
functionality. This is one of the essential concepts behind creating
custom widgets or collections of standard widgets. Subclassing to
extend or change the behavior of a widget has the following advantages:
\list
\li We can write implementations of virtual or pure virtual functions to
obtain exactly what we need, falling back on the base class's implementation
when necessary.
\li It allows us to encapsulate parts of the user interface within a class,
so that the other parts of the application don't need to know about the
individual widgets in the user interface.
\li The subclass can be used to create multiple custom widgets in the same
application or library, and the code for the subclass can be reused in other
projects.
\endlist
Since Qt does not provide a specific address book widget, we subclass a
standard Qt widget class and add features to it. The \c AddressBook class
we create in this tutorial can be reused in situations where a basic address
book widget is needed.
\section1 Defining the AddressBook Class
The \c{tutorials/addressbook/part1/addressbook.h} file is
used to define the \c AddressBook class.
We start by defining \c AddressBook as a QWidget subclass and declaring
a constructor. We also use the Q_OBJECT macro to indicate that the class
uses internationalization and Qt's signals and slots features, even
if we do not use all of these features at this stage.
\snippet tutorials/addressbook/part1/addressbook.h class definition
The class holds declarations of \c nameLine and \c addressText,
the private instances of QLineEdit and QTextEdit mentioned
earlier. The data stored in \c nameLine and \c addressText will
be needed for many of the address book functions.
We don't include declarations of the QLabel objects we will use
because we will not need to reference them once they have been
created. The way Qt tracks the ownership of objects is explained
in the next section.
The Q_OBJECT macro itself implements some of the more advanced features of Qt.
For now, it is useful to think of the Q_OBJECT macro as a shortcut which allows
us to use the \l{QObject::}{tr()} and \l{QObject::}{connect()} functions.
We have now completed the \c addressbook.h file and we move on to
implement the corresponding \c addressbook.cpp file.
\section1 Implementing the AddressBook Class
The constructor of \c AddressBook accepts a QWidget parameter, \a parent.
By convention, we pass this parameter to the base class's constructor.
This concept of ownership, where a parent can have one or more children,
is useful for grouping widgets in Qt. For example, if you delete a parent,
all of its children will be deleted as well.
\snippet tutorials/addressbook/part1/addressbook.cpp constructor and input fields
In this constructor, the QLabel objects \c nameLabel and \c
addressLabel are instantiated, as well as \c nameLine and \c
addressText. The \l{QObject::tr()}{tr()} function returns a
translated version of the string, if there is one
available. Otherwise it returns the string itself. This function
marks its QString parameter as one that should be translated into
other languages. It should be used wherever a translatable string
appears.
When programming with Qt, it is useful to know how layouts work.
Qt provides three main layout classes: QHBoxLayout, QVBoxLayout
and QGridLayout to handle the positioning of widgets.
\image addressbook-tutorial-part1-labeled-layout.png
We use a QGridLayout to position our labels and input fields in a
structured manner. QGridLayout divides the available space into a grid and
places widgets in the cells we specify with row and column numbers. The
diagram above shows the layout cells and the position of our widgets, and
we specify this arrangement using the following code:
\snippet tutorials/addressbook/part1/addressbook.cpp layout
Notice that \c addressLabel is positioned using Qt::AlignTop as an
additional argument. This is to make sure it is not vertically centered in
cell (1,0). For a basic overview on Qt Layouts, refer to the
\l{Layout Management} documentation.
In order to install the layout object onto the widget, we have to invoke
the widget's \l{QWidget::setLayout()}{setLayout()} function:
\snippet tutorials/addressbook/part1/addressbook.cpp setting the layout
Lastly, we set the widget's title to "Simple Address Book".
\section1 Running the Application
A separate file, \c main.cpp, is used for the \c main() function. Within
this function, we instantiate a QApplication object, \c app. QApplication
is responsible for various application-wide resources, such as the default
font and cursor, and for running an event loop. Hence, there is always one
QApplication object in every GUI application using Qt.
\snippet tutorials/addressbook/part1/main.cpp main function
We construct a new \c AddressBook widget on the stack and invoke
its \l{QWidget::show()}{show()} function to display it.
However, the widget will not be shown until the application's event loop
is started. We start the event loop by calling the application's
\l{QApplication::}{exec()} function; the result returned by this function
is used as the return value from the \c main() function. At this point,
it becomes apparent why we instantiated \c AddressBook on the stack: It
will now go out of scope. Therefore, \c AddressBook and all its child widgets
will be deleted, thus preventing memory leaks.
*/
/*!
\example tutorials/addressbook/part2
\title Part 2 - Adding Addresses
\brief Describes the code for inserting records in the Address Book Example.
The next step in creating the address book is to implement some
user interactions.
\image addressbook-tutorial-part2-add-contact.png
We will provide a push button that the user can click to add a new contact.
Also, some form of data structure is needed to store these contacts in an
organized way.
\section1 Defining the AddressBook Class
Now that we have the labels and input fields set up, we add push buttons to
complete the process of adding a contact. This means that our
\c addressbook.h file now has three QPushButton objects declared and three
corresponding public slots.
\snippet tutorials/addressbook/part2/addressbook.h slots
A slot is a function that responds to a particular signal. We will discuss
this concept in further detail when implementing the \c AddressBook class.
However, for an overview of Qt's signals and slots concept, you can refer
to the \l{Signals and Slots} document.
Three QPushButton objects (\c addButton, \c submitButton, and
\c cancelButton) are now included in our private variable declarations,
along with \c nameLine and \c addressText.
\snippet tutorials/addressbook/part2/addressbook.h pushbutton declaration
We need a container to store our address book contacts, so that we can
traverse and display them. A QMap object, \c contacts, is used for this
purpose as it holds a key-value pair: the contact's name as the \e key,
and the contact's address as the \e{value}.
\snippet tutorials/addressbook/part2/addressbook.h remaining private variables
We also declare two private QString objects, \c oldName and \c oldAddress.
These objects are needed to hold the name and address of the contact that
was last displayed, before the user clicked \uicontrol Add. So, when the user clicks
\uicontrol Cancel, we can revert to displaying the details of the last contact.
\section1 Implementing the AddressBook Class
Within the constructor of \c AddressBook, we set the \c nameLine and
\c addressText to read-only, so that we can only display but not edit
existing contact details.
\dots
\snippet tutorials/addressbook/part2/addressbook.cpp setting readonly 1
\dots
\snippet tutorials/addressbook/part2/addressbook.cpp setting readonly 2
Then, we instantiate our push buttons: \c addButton, \c submitButton, and
\c cancelButton.
\snippet tutorials/addressbook/part2/addressbook.cpp pushbutton declaration
The \c addButton is displayed by invoking the \l{QPushButton::show()}
{show()} function, while the \c submitButton and \c cancelButton are
hidden by invoking \l{QPushButton::hide()}{hide()}. These two push
buttons will only be displayed when the user clicks \uicontrol Add and this is
handled by the \c addContact() function discussed below.
\snippet tutorials/addressbook/part2/addressbook.cpp connecting signals and slots
We connect the push buttons' \l{QPushButton::clicked()}{clicked()} signal
to their respective slots. The figure below illustrates this.
\image addressbook-tutorial-part2-signals-and-slots.png
Next, we arrange our push buttons neatly to the right of our address book
widget, using a QVBoxLayout to line them up vertically.
\snippet tutorials/addressbook/part2/addressbook.cpp vertical layout
The \l{QBoxLayout::addStretch()}{addStretch()} function is used to ensure
the push buttons are not evenly spaced, but arranged closer to the top of
the widget. The figure below shows the difference between using
\l{QBoxLayout::addStretch()}{addStretch()} and not using it.
\image addressbook-tutorial-part2-stretch-effects.png
We then add \c buttonLayout1 to \c mainLayout, using
\l{QGridLayout::addLayout()}{addLayout()}. This gives us nested layouts
as \c buttonLayout1 is now a child of \c mainLayout.
\snippet tutorials/addressbook/part2/addressbook.cpp grid layout
Our layout coordinates now look like this:
\image addressbook-tutorial-part2-labeled-layout.png
In the \c addContact() function, we store the last displayed contact
details in \c oldName and \c oldAddress. Then we clear these input
fields and turn off the read-only mode. The focus is set on \c nameLine
and we display \c submitButton and \c cancelButton.
\snippet tutorials/addressbook/part2/addressbook.cpp addContact
The \c submitContact() function can be divided into three parts:
\list 1
\li We extract the contact's details from \c nameLine and \c addressText
and store them in QString objects. We also validate to make sure that the
user did not click \uicontrol Submit with empty input fields; otherwise, a
QMessageBox is displayed to remind the user for a name and address.
\snippet tutorials/addressbook/part2/addressbook.cpp submitContact part1
\li We then proceed to check if the contact already exists. If it does not
exist, we add the contact to \c contacts and we display a QMessageBox to
inform the user that the contact has been added.
\snippet tutorials/addressbook/part2/addressbook.cpp submitContact part2
If the contact already exists, again, we display a QMessageBox to inform
the user about this, preventing the user from adding duplicate contacts.
Our \c contacts object is based on key-value pairs of name and address,
hence, we want to ensure that \e key is unique.
\li Once we have handled both cases mentioned above, we restore the push
buttons to their normal state with the following code:
\snippet tutorials/addressbook/part2/addressbook.cpp submitContact part3
\endlist
The screenshot below shows the QMessageBox object we use to display
information messages to the user.
\image addressbook-tutorial-part2-add-successful.png
The \c cancel() function restores the last displayed contact details and
enables \c addButton, as well as hides \c submitButton and
\c cancelButton.
\snippet tutorials/addressbook/part2/addressbook.cpp cancel
The general idea behind adding a contact is to give the user the
flexibility to click \uicontrol Submit or \uicontrol Cancel at any time. The flowchart below
further explains this concept:
\image addressbook-tutorial-part2-add-flowchart.png
*/
/*!
\example tutorials/addressbook/part3
\title Part 3 - Navigating between Entries
\brief Explains the code that enables navigating the contacts.
The address book is now about half complete. We should add the
capability to navigate the contacts, but first we must
decide what sort of a data structure we need for containing these
contacts.
In the previous section, we used a QMap of key-value pairs with
the contact's name as the \e key, and the contact's address as the
\e value. This works well for our case. However, in order to
navigate and display each entry, a little bit of enhancement is
needed.
We enhance the QMap by making it replicate a data structure similar to a
circularly-linked list, where all elements are connected, including the
first element and the last element. The figure below illustrates this data
structure.
\image addressbook-tutorial-part3-linkedlist.png
\section1 Defining the AddressBook Class
To add navigation functions to the address book, we must add two
more slots to the \c AddressBook class: \c next() and \c
previous() to the \c addressbook.h file:
\snippet tutorials/addressbook/part3/addressbook.h navigation functions
We also require another two QPushButton objects, so we declare \c nextButton
and \c previousButton as private variables:
\snippet tutorials/addressbook/part3/addressbook.h navigation pushbuttons
\section1 Implementing the AddressBook Class
In the \c AddressBook constructor in \c addressbook.cpp, we instantiate
\c nextButton and \c previousButton and disable them by default. This is
because navigation is only enabled when there is more than one contact
in the address book.
\snippet tutorials/addressbook/part3/addressbook.cpp navigation pushbuttons
We then connect these push buttons to their respective slots:
\snippet tutorials/addressbook/part3/addressbook.cpp connecting navigation signals
The image below is the expected graphical user interface.
\image addressbook-tutorial-part3-screenshot.png
We follow basic conventions for \c next() and \c previous() functions by
placing the \c nextButton on the right and the \c previousButton on the
left. In order to achieve this intuitive layout, we use QHBoxLayout to
place the widgets side-by-side:
\snippet tutorials/addressbook/part3/addressbook.cpp navigation layout
The QHBoxLayout object, \c buttonLayout2, is then added to \c mainLayout.
\snippet tutorials/addressbook/part3/addressbook.cpp adding navigation layout
The figure below shows the coordinates of the widgets in \c mainLayout.
\image addressbook-tutorial-part3-labeled-layout.png
Within our \c addContact() function, we have to disable these buttons so
that the user does not attempt to navigate while adding a contact.
\snippet tutorials/addressbook/part3/addressbook.cpp disabling navigation
Also, in our \c submitContact() function, we enable the navigation
buttons, \c nextButton and \c previousButton, depending on the size
of \c contacts. As mentioned earlier, navigation is only enabled when
there is more than one contact in the address book. The following lines
of code demonstrates how to do this:
\snippet tutorials/addressbook/part3/addressbook.cpp enabling navigation
We also include these lines of code in the \c cancel() function.
Recall that we intend to emulate a circularly-linked list with our QMap
object, \c contacts. So, in the \c next() function, we obtain an iterator
for \c contacts and then:
\list
\li If the iterator is not at the end of \c contacts, we increment it
by one.
\li If the iterator is at the end of \c contacts, we move it to the
beginning of \c contacts. This gives us the illusion that our QMap is
working like a circularly-linked list.
\endlist
\snippet tutorials/addressbook/part3/addressbook.cpp next() function
Once we have iterated to the correct object in \c contacts, we display
its contents on \c nameLine and \c addressText.
Similarly, for the \c previous() function, we obtain an iterator for
\c contacts and then:
\list
\li If the iterator is at the end of \c contacts, we clear the
display and return.
\li If the iterator is at the beginning of \c contacts, we move it to
the end.
\li We then decrement the iterator by one.
\endlist
\snippet tutorials/addressbook/part3/addressbook.cpp previous() function
Again, we display the contents of the current object in \c contacts.
*/
/*!
\example tutorials/addressbook/part4
\title Part 4 - Editing and Removing Addresses
\brief Explains how to add edit and remove functionality.
Now we look at ways to modify the contents of contacts stored in
the address book.
\image addressbook-tutorial-screenshot.png
We now have an address book that not only holds contacts in an
organized manner, but also allows navigation. It would be
convenient to include edit and remove functions so that a
contact's details can be changed when needed. However, this
requires a little improvement, in the form of enums. We defined
two modes: \c{AddingMode} and \c{NavigationMode}, but they were
not defined as enum values. Instead, we enabled and disabled the
corresponding buttons manually, resulting in multiple lines of
repeated code.
Here we define the \c Mode enum with three different values:
\list
\li \c{NavigationMode},
\li \c{AddingMode}, and
\li \c{EditingMode}.
\endlist
\section1 Defining the AddressBook Class
The \c addressbook.h file is updated to contain the \c Mode enum:
\snippet tutorials/addressbook/part4/addressbook.h Mode enum
We also add two new slots, \c editContact() and \c removeContact(), to
our current list of public slots.
\snippet tutorials/addressbook/part4/addressbook.h edit and remove slots
In order to switch between modes, we introduce the \c updateInterface() function
to control the enabling and disabling of all QPushButton objects. We also
add two new push buttons, \c editButton and \c removeButton, for the edit
and remove functions mentioned earlier.
\snippet tutorials/addressbook/part4/addressbook.h updateInterface() declaration
\dots
\snippet tutorials/addressbook/part4/addressbook.h buttons declaration
\dots
\snippet tutorials/addressbook/part4/addressbook.h mode declaration
Lastly, we declare \c currentMode to keep track of the enum's current mode.
\section1 Implementing the AddressBook Class
We now implement the mode-changing features of the address
book. The \c editButton and \c removeButton are instantiated and
disabled by default. The address book starts with zero contacts
in memory.
\snippet tutorials/addressbook/part4/addressbook.cpp edit and remove buttons
These buttons are then connected to their respective slots, \c editContact()
and \c removeContact(), and we add them to \c buttonLayout1.
\snippet tutorials/addressbook/part4/addressbook.cpp connecting edit and remove
\dots
\snippet tutorials/addressbook/part4/addressbook.cpp adding edit and remove to the layout
The \c editContact() function stores the contact's old details in
\c oldName and \c oldAddress, before switching the mode to \c EditingMode.
In this mode, the \c submitButton and \c cancelButton are both enabled,
hence, the user can change the contact's details and click either button.
\snippet tutorials/addressbook/part4/addressbook.cpp editContact() function
The \c submitContact() function has been divided in two with an \c{if-else}
statement. We check \c currentMode to see if it's in \c AddingMode. If it is,
we proceed with our adding process.
\snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function beginning
\dots
\snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function part1
Otherwise, we check to see if \c currentMode is in \c EditingMode. If it
is, we compare \c oldName with \c name. If the name has changed, we remove
the old contact from \c contacts and insert the newly updated contact.
\snippet tutorials/addressbook/part4/addressbook.cpp submitContact() function part2
If only the address has changed (i.e., \c oldAddress is not the same as \c address),
we update the contact's address. Lastly, we set \c currentMode to
\c NavigationMode. This is an important step as it re-enables all the
disabled push buttons.
To remove a contact from the address book, we implement the
\c removeContact() function. This function checks to see if the contact
exists in \c contacts.
\snippet tutorials/addressbook/part4/addressbook.cpp removeContact() function
If it does, we display a QMessageBox, to confirm the removal with the
user. Once the user has confirmed, we call \c previous() to ensure that the
user interface shows another contact, and we remove the contact using \l{QMap}'s
\l{QMap::remove()}{remove()} function. As a courtesy, we display a QMessageBox
to inform the user. Both the message boxes used in this function are shown below:
\image addressbook-tutorial-part4-remove.png
\section2 Updating the User Interface
We mentioned the \c updateInterface() function earlier as a means to
enable and disable the push buttons depending on the current mode.
The function updates the current mode according to the \c mode argument
passed to it, assigning it to \c currentMode before checking its value.
Each of the push buttons is then enabled or disabled, depending on the
current mode. The code for \c AddingMode and \c EditingMode is shown below:
\snippet tutorials/addressbook/part4/addressbook.cpp update interface() part 1
For \c NavigationMode, however, we include conditions within the parameters
of the QPushButton::setEnabled() function. This is to ensure that
\c editButton and \c removeButton are enabled when there is at least one
contact in the address book; \c nextButton and \c previousButton are only
enabled when there is more than one contact in the address book.
\snippet tutorials/addressbook/part4/addressbook.cpp update interface() part 2
By setting the mode and updating the user interface in the same
function, we avoid the possibility of the user interface getting
out of sync with the internal state of the application.
*/
/*!
\example tutorials/addressbook/part5
\title Part 5 - Adding a Find Function
\brief Describes how to add a find function.
Here we look at ways to locate contacts and addresses in the
address book.
\image addressbook-tutorial-part5-screenshot.png
As we add contacts to our address book, it becomes tedious to
navigate the list with the \e Next and \e Previous buttons. A \e
Find function would be more efficient. The screenshot above shows
the \e Find button and its position on the panel of buttons.
When the user clicks on the \e Find button, it is useful to
display a dialog that prompts for a contact's name. Qt provides
QDialog, which we subclass here to implement a \c FindDialog
class.
\section1 Defining the FindDialog Class
\image addressbook-tutorial-part5-finddialog.png
In order to subclass QDialog, we first include the header for QDialog in
the \c finddialog.h file. Also, we use forward declaration to declare
QLineEdit and QPushButton since we will be using those widgets in our
dialog class.
As in our \c AddressBook class, the \c FindDialog class includes
the Q_OBJECT macro and its constructor is defined to accept a parent
QWidget, even though the dialog will be opened as a separate window.
\snippet tutorials/addressbook/part5/finddialog.h FindDialog header
We define a public function, \c getFindText(), to be used by classes that
instantiate \c FindDialog. This function allows these classes to obtain the
search string entered by the user. A public slot, \c findClicked(), is also
defined to handle the search string when the user clicks the \uicontrol Find
button.
Lastly, we define the private variables, \c findButton, \c lineEdit
and \c findText, corresponding to the \uicontrol Find button, the line edit
into which the user types the search string, and an internal string
used to store the search string for later use.
\section1 Implementing the FindDialog Class
Within the constructor of \c FindDialog, we set up the private variables,
\c lineEdit, \c findButton and \c findText. We use a QHBoxLayout to
position the widgets.
\snippet tutorials/addressbook/part5/finddialog.cpp constructor
We set the layout and window title, as well as connect the signals to their
respective slots. Notice that \c{findButton}'s \l{QPushButton::clicked()}
{clicked()} signal is connected to \c findClicked() and
\l{QDialog::accept()}{accept()}. The \l{QDialog::accept()}{accept()} slot
provided by QDialog hides the dialog and sets the result code to
\l{QDialog::}{Accepted}. We use this function to help \c{AddressBook}'s
\c findContact() function know when the \c FindDialog object has been
closed. We will explain this logic in further detail when discussing the
\c findContact() function.
\image addressbook-tutorial-part5-signals-and-slots.png
In \c findClicked(), we validate \c lineEdit to ensure that the user
did not click the \uicontrol Find button without entering a contact's name. Then, we set
\c findText to the search string, extracted from \c lineEdit. After that,
we clear the contents of \c lineEdit and hide the dialog.
\snippet tutorials/addressbook/part5/finddialog.cpp findClicked() function
The \c findText variable has a public getter function, \c getFindText(),
associated with it. Since we only ever set \c findText directly in both the
constructor and in the \c findClicked() function, we do not create a
setter function to accompany \c getFindText().
Because \c getFindText() is public, classes instantiating and using
\c FindDialog can always access the search string that the user has
entered and accepted.
\snippet tutorials/addressbook/part5/finddialog.cpp getFindText() function
\section1 Defining the AddressBook Class
To ensure we can use \c FindDialog from within our \c AddressBook class, we
include \c finddialog.h in the \c addressbook.h file.
\snippet tutorials/addressbook/part5/addressbook.h include finddialog's header
So far, all our address book features have a QPushButton and a
corresponding slot. Similarly, for the \uicontrol Find feature we have
\c findButton and \c findContact().
The \c findButton is declared as a private variable and the
\c findContact() function is declared as a public slot.
\snippet tutorials/addressbook/part5/addressbook.h findContact() declaration
\dots
\snippet tutorials/addressbook/part5/addressbook.h findButton declaration
Lastly, we declare the private variable, \c dialog, which we will use to
refer to an instance of \c FindDialog.
\snippet tutorials/addressbook/part5/addressbook.h FindDialog declaration
Once we have instantiated a dialog, we will want to use it more than once;
using a private variable allows us to refer to it from more than one place
in the class.
\section1 Implementing the AddressBook Class
Within the \c AddressBook class's constructor, we instantiate our private
objects, \c findButton and \c findDialog:
\snippet tutorials/addressbook/part5/addressbook.cpp instantiating findButton
\dots
\snippet tutorials/addressbook/part5/addressbook.cpp instantiating FindDialog
Next, we connect the \c{findButton}'s
\l{QPushButton::clicked()}{clicked()} signal to \c findContact().
\snippet tutorials/addressbook/part5/addressbook.cpp signals and slots for find
Now all that is left is the code for our \c findContact() function:
\snippet tutorials/addressbook/part5/addressbook.cpp findContact() function
We start out by displaying the \c FindDialog instance, \c dialog. This is
when the user enters a contact name to look up. Once the user clicks
the dialog's \c findButton, the dialog is hidden and the result code is
set to QDialog::Accepted. This ensures that
our \c if statement is always true.
We then proceed to extract the search string, which in this case is
\c contactName, using \c{FindDialog}'s \c getFindText() function. If the
contact exists in our address book, we display it immediately. Otherwise,
we display the QMessageBox shown below to indicate that their search
failed.
\image addressbook-tutorial-part5-notfound.png
*/
/*!
\example tutorials/addressbook/part6
\title Part 6 - Loading and Saving
\brief Describes how to add save and load functionality.
This part covers the Qt file handling features we use to write
loading and saving routines for the address book.
\image addressbook-tutorial-part6-screenshot.png
Although browsing and searching the contact list are useful
features, our address book is not complete until we can save
existing contacts and load them again at a later time.
Qt provides a number of classes for \l{Input/Output and Networking}
{input and output}, but we have chosen to use two which are simple to use
in combination: QFile and QDataStream.
A QFile object represents a file on disk that can be read from and written
to. QFile is a subclass of the more general QIODevice class which
represents many different kinds of devices.
A QDataStream object is used to serialize binary data so that it can be
stored in a QIODevice and retrieved again later. Reading from a QIODevice
and writing to it is as simple as opening the stream - with the respective
device as a parameter - and reading from or writing to it.
\section1 Defining the AddressBook Class
We declare two public slots, \c saveToFile() and \c loadFromFile(), as well
as two QPushButton objects, \c loadButton and \c saveButton.
\snippet tutorials/addressbook/part6/addressbook.h save and load functions declaration
\dots
\snippet tutorials/addressbook/part6/addressbook.h save and load buttons declaration
\section1 Implementing the AddressBook Class
In our constructor, we instantiate \c loadButton and \c saveButton.
Ideally, it would be more user-friendly to set the push buttons' labels
to "Load contacts from a file" and "Save contacts to a file". However, due
to the size of our other push buttons, we set the labels to \uicontrol{Load...}
and \uicontrol{Save...}. Fortunately, Qt provides a simple way to set tooltips with
\l{QWidget::setToolTip()}{setToolTip()} and we use it in the following way
for our push buttons:
\snippet tutorials/addressbook/part6/addressbook.cpp tooltip 1
\dots
\snippet tutorials/addressbook/part6/addressbook.cpp tooltip 2
Although it is not shown here, just like the other features we implemented,
we add the push buttons to the layout panel on the right, \c buttonLayout1,
and we connect the push buttons' \l{QPushButton::clicked()}{clicked()}
signals to their respective slots.
For the saving feature, we first obtain \c fileName using
QFileDialog::getSaveFileName(). This is a convenience function provided
by QFileDialog, which pops up a modal file dialog and allows the user to
enter a file name or select any existing \c{.abk} file. The \c{.abk} file
is our Address Book extension that we create when we save contacts.
\snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part1
The file dialog that pops up is displayed in the screenshot below:
\image addressbook-tutorial-part6-save.png
If \c fileName is not empty, we create a QFile object, \c file, with
\c fileName. QFile works with QDataStream as QFile is a QIODevice.
Next, we attempt to open the file in \l{QIODeviceBase::}{WriteOnly} mode.
If this is unsuccessful, we display a QMessageBox to inform the user.
\snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part2
Otherwise, we instantiate a QDataStream object, \c out, to write the open
file. QDataStream requires that the same version of the stream is used
for reading and writing. We ensure that this is the case by setting the
version used to the \l{QDataStream::Qt_4_5}{version introduced with Qt 4.5}
before serializing the data to \c file.
\snippet tutorials/addressbook/part6/addressbook.cpp saveToFile() function part3
For the loading feature, we also obtain \c fileName using
QFileDialog::getOpenFileName(). This function, the counterpart to
QFileDialog::getSaveFileName(), also pops up the modal file dialog and
allows the user to enter a file name or select any existing \c{.abk} file
to load it into the address book.
\snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part1
On Windows, for example, this function pops up a native file dialog, as
shown in the following screenshot.
\image addressbook-tutorial-part6-load.png
If \c fileName is not empty, again, we use a QFile object, \c file, and
attempt to open it in \l{QIODeviceBase::}{ReadOnly} mode. Similar to our
implementation of \c saveToFile(), if this attempt is unsuccessful, we
display a QMessageBox to inform the user.
\snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part2
Otherwise, we instantiate a QDataStream object, \c in, set its version as
above and read the serialized data into the \c contacts data structure.
The \c contacts object is emptied before data is read into it to simplify
the file reading process. A more advanced method would be to read the
contacts into a temporary QMap object, and copy over non-duplicate contacts
into \c contacts.
\snippet tutorials/addressbook/part6/addressbook.cpp loadFromFile() function part3
To display the contacts that have been read from the file, we must first
validate the data obtained to ensure that the file we read from actually
contains address book contacts. If it does, we display the first contact;
otherwise, we display a QMessageBox to inform the user about the problem.
Lastly, we update the interface to enable and disable the push buttons
accordingly.
*/
/*!
\example tutorials/addressbook/part7
\title Part 7 - Additional Features
\brief Describes how to export data in VCard format.
This part covers some additional features that make the address
book more convenient for the frequent user.
\image addressbook-tutorial-part7-screenshot.png
Although our address book is useful in isolation, it would be
better if we could exchange contact data with other applications.
The vCard format is a popular file format that can be used for
this purpose. Here we extend our address book client to allow
contacts to be exported to vCard \c{.vcf} files.
\section1 Defining the AddressBook Class
We add a QPushButton object, \c exportButton, and a corresponding public
slot, \c exportAsVCard() to our \c AddressBook class in the
\c addressbook.h file.
\snippet tutorials/addressbook/part7/addressbook.h exportAsVCard() declaration
\dots
\snippet tutorials/addressbook/part7/addressbook.h exportButton declaration
\section1 Implementing the AddressBook Class
Within the \c AddressBook constructor, we connect \c{exportButton}'s
\l{QPushButton::clicked()}{clicked()} signal to \c exportAsVCard().
We also add this button to our \c buttonLayout1, the layout responsible
for our panel of buttons on the right.
In our \c exportAsVCard() function, we start by extracting the contact's
name into \c name. We declare \c firstName, \c lastName and \c nameList.
Next, we look for the index of the first white space in \c name. If there
is a white space, we split the contact's name into \c firstName and
\c lastName. Then, we replace the space with an underscore ("_").
Alternately, if there is no white space, we assume that the contact only
has a first name.
\snippet tutorials/addressbook/part7/addressbook.cpp export function part1
As with the \c saveToFile() function, we open a file dialog to let the user
choose a location for the file. Using the file name chosen, we create an
instance of QFile to write to.
We attempt to open the file in \l{QIODeviceBase::}{WriteOnly} mode. If this
process fails, we display a QMessageBox to inform the user about the
problem and return. Otherwise, we pass the file as a parameter to a
QTextStream object, \c out. Like QDataStream, the QTextStream class
provides functionality to read and write plain text to files. As a result,
the \c{.vcf} file generated can be opened for editing in a text editor.
\snippet tutorials/addressbook/part7/addressbook.cpp export function part2
We then write out a vCard file with the \c{BEGIN:VCARD} tag, followed by
the \c{VERSION:2.1} tag. The contact's name is written with the \c{N:}
tag. For the \c{FN:} tag, which fills in the "File as" property of a vCard,
we have to check whether the contact has a last name or not. If the contact
does, we use the details in \c nameList to fill it. Otherwise, we write
\c firstName only.
\snippet tutorials/addressbook/part7/addressbook.cpp export function part3
We proceed to write the contact's address. The semicolons in the address
are escaped with "\\", the newlines are replaced with semicolons, and the
commas are replaced with spaces. Lastly, we write the \c{ADR;HOME:;}
tag, followed by \c address and then the \c{END:VCARD} tag.
\snippet tutorials/addressbook/part7/addressbook.cpp export function part4
In the end, a QMessageBox is displayed to inform the user that the vCard
has been successfully exported.
\e{vCard is a trademark of the \l{http://www.imc.org}
{Internet Mail Consortium}}.
*/

View File

@ -0,0 +1,6 @@
TEMPLATE = subdirs
SUBDIRS = part1 part2 part3 part4 part5 part6 part7
# install
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/tutorials/addressbook
INSTALLS += target

View File

@ -0,0 +1,37 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(part1 LANGUAGES CXX)
if(NOT DEFINED INSTALL_EXAMPLESDIR)
set(INSTALL_EXAMPLESDIR "examples")
endif()
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/tutorials/addressbook/part1")
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
qt_standard_project_setup()
qt_add_executable(part1
addressbook.cpp addressbook.h
main.cpp
)
set_target_properties(part1 PROPERTIES
WIN32_EXECUTABLE TRUE
MACOSX_BUNDLE TRUE
)
target_link_libraries(part1 PRIVATE
Qt6::Core
Qt6::Gui
Qt6::Widgets
)
install(TARGETS part1
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
)

View File

@ -0,0 +1,30 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QtWidgets>
#include "addressbook.h"
//! [constructor and input fields]
AddressBook::AddressBook(QWidget *parent)
: QWidget(parent)
{
QLabel *nameLabel = new QLabel(tr("Name:"));
nameLine = new QLineEdit;
QLabel *addressLabel = new QLabel(tr("Address:"));
addressText = new QTextEdit;
//! [constructor and input fields]
//! [layout]
QGridLayout *mainLayout = new QGridLayout;
mainLayout->addWidget(nameLabel, 0, 0);
mainLayout->addWidget(nameLine, 0, 1);
mainLayout->addWidget(addressLabel, 1, 0, Qt::AlignTop);
mainLayout->addWidget(addressText, 1, 1);
//! [layout]
//![setting the layout]
setLayout(mainLayout);
setWindowTitle(tr("Simple Address Book"));
}
//! [setting the layout]

View File

@ -0,0 +1,29 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef ADDRESSBOOK_H
#define ADDRESSBOOK_H
#include <QWidget>
QT_BEGIN_NAMESPACE
class QLabel;
class QLineEdit;
class QTextEdit;
QT_END_NAMESPACE
//! [class definition]
class AddressBook : public QWidget
{
Q_OBJECT
public:
AddressBook(QWidget *parent = nullptr);
private:
QLineEdit *nameLine;
QTextEdit *addressText;
};
//! [class definition]
#endif

View File

@ -0,0 +1,17 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QtWidgets>
#include "addressbook.h"
//! [main function]
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
AddressBook addressBook;
addressBook.show();
return app.exec();
}
//! [main function]

View File

@ -0,0 +1,11 @@
QT += widgets
SOURCES = addressbook.cpp \
main.cpp
HEADERS = addressbook.h
QMAKE_PROJECT_NAME = ab_part1
# install
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/tutorials/addressbook/part1
INSTALLS += target

View File

@ -0,0 +1,37 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(part2 LANGUAGES CXX)
if(NOT DEFINED INSTALL_EXAMPLESDIR)
set(INSTALL_EXAMPLESDIR "examples")
endif()
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/tutorials/addressbook/part2")
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
qt_standard_project_setup()
qt_add_executable(part2
addressbook.cpp addressbook.h
main.cpp
)
set_target_properties(part2 PROPERTIES
WIN32_EXECUTABLE TRUE
MACOSX_BUNDLE TRUE
)
target_link_libraries(part2 PRIVATE
Qt6::Core
Qt6::Gui
Qt6::Widgets
)
install(TARGETS part2
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
)

View File

@ -0,0 +1,123 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QtWidgets>
#include "addressbook.h"
AddressBook::AddressBook(QWidget *parent)
: QWidget(parent)
{
QLabel *nameLabel = new QLabel(tr("Name:"));
nameLine = new QLineEdit;
//! [setting readonly 1]
nameLine->setReadOnly(true);
//! [setting readonly 1]
QLabel *addressLabel = new QLabel(tr("Address:"));
addressText = new QTextEdit;
//! [setting readonly 2]
addressText->setReadOnly(true);
//! [setting readonly 2]
//! [pushbutton declaration]
addButton = new QPushButton(tr("&Add"));
addButton->show();
submitButton = new QPushButton(tr("&Submit"));
submitButton->hide();
cancelButton = new QPushButton(tr("&Cancel"));
cancelButton->hide();
//! [pushbutton declaration]
//! [connecting signals and slots]
connect(addButton, &QPushButton::clicked,
this, &AddressBook::addContact);
connect(submitButton, &QPushButton::clicked,
this, &AddressBook::submitContact);
connect(cancelButton, &QPushButton::clicked,
this, &AddressBook::cancel);
//! [connecting signals and slots]
//! [vertical layout]
QVBoxLayout *buttonLayout1 = new QVBoxLayout;
buttonLayout1->addWidget(addButton, Qt::AlignTop);
buttonLayout1->addWidget(submitButton);
buttonLayout1->addWidget(cancelButton);
buttonLayout1->addStretch();
//! [vertical layout]
//! [grid layout]
QGridLayout *mainLayout = new QGridLayout;
mainLayout->addWidget(nameLabel, 0, 0);
mainLayout->addWidget(nameLine, 0, 1);
mainLayout->addWidget(addressLabel, 1, 0, Qt::AlignTop);
mainLayout->addWidget(addressText, 1, 1);
mainLayout->addLayout(buttonLayout1, 1, 2);
//! [grid layout]
setLayout(mainLayout);
setWindowTitle(tr("Simple Address Book"));
}
//! [addContact]
void AddressBook::addContact()
{
oldName = nameLine->text();
oldAddress = addressText->toPlainText();
nameLine->clear();
addressText->clear();
nameLine->setReadOnly(false);
nameLine->setFocus(Qt::OtherFocusReason);
addressText->setReadOnly(false);
addButton->setEnabled(false);
submitButton->show();
cancelButton->show();
}
//! [addContact]
//! [submitContact part1]
void AddressBook::submitContact()
{
QString name = nameLine->text();
QString address = addressText->toPlainText();
if (name.isEmpty() || address.isEmpty()) {
QMessageBox::information(this, tr("Empty Field"),
tr("Please enter a name and address."));
return;
}
//! [submitContact part1]
//! [submitContact part2]
if (!contacts.contains(name)) {
contacts.insert(name, address);
QMessageBox::information(this, tr("Add Successful"),
tr("\"%1\" has been added to your address book.").arg(name));
} else {
QMessageBox::information(this, tr("Add Unsuccessful"),
tr("Sorry, \"%1\" is already in your address book.").arg(name));
return;
}
//! [submitContact part2]
//! [submitContact part3]
if (contacts.isEmpty()) {
nameLine->clear();
addressText->clear();
}
nameLine->setReadOnly(true);
addressText->setReadOnly(true);
addButton->setEnabled(true);
submitButton->hide();
cancelButton->hide();
}
//! [submitContact part3]
//! [cancel]
void AddressBook::cancel()
{
nameLine->setText(oldName);
nameLine->setReadOnly(true);
addressText->setText(oldAddress);
addressText->setReadOnly(true);
addButton->setEnabled(true);
submitButton->hide();
cancelButton->hide();
}
//! [cancel]

View File

@ -0,0 +1,47 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef ADDRESSBOOK_H
#define ADDRESSBOOK_H
#include <QWidget>
#include <QMap>
QT_BEGIN_NAMESPACE
class QLabel;
class QLineEdit;
class QPushButton;
class QTextEdit;
QT_END_NAMESPACE
class AddressBook : public QWidget
{
Q_OBJECT
public:
AddressBook(QWidget *parent = nullptr);
//! [slots]
public slots:
void addContact();
void submitContact();
void cancel();
//! [slots]
//! [pushbutton declaration]
private:
QPushButton *addButton;
QPushButton *submitButton;
QPushButton *cancelButton;
QLineEdit *nameLine;
QTextEdit *addressText;
//! [pushbutton declaration]
//! [remaining private variables]
QMap<QString, QString> contacts;
QString oldName;
QString oldAddress;
};
//! [remaining private variables]
#endif

View File

@ -0,0 +1,17 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QtWidgets>
#include "addressbook.h"
//! [main function]
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
AddressBook addressBook;
addressBook.show();
return app.exec();
}
//! [main function]

View File

@ -0,0 +1,11 @@
QT += widgets
SOURCES = addressbook.cpp \
main.cpp
HEADERS = addressbook.h
QMAKE_PROJECT_NAME = ab_part2
# install
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/tutorials/addressbook/part2
INSTALLS += target

View File

@ -0,0 +1,37 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(part3 LANGUAGES CXX)
if(NOT DEFINED INSTALL_EXAMPLESDIR)
set(INSTALL_EXAMPLESDIR "examples")
endif()
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/tutorials/addressbook/part3")
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
qt_standard_project_setup()
qt_add_executable(part3
addressbook.cpp addressbook.h
main.cpp
)
set_target_properties(part3 PROPERTIES
WIN32_EXECUTABLE TRUE
MACOSX_BUNDLE TRUE
)
target_link_libraries(part3 PRIVATE
Qt6::Core
Qt6::Gui
Qt6::Widgets
)
install(TARGETS part3
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
)

View File

@ -0,0 +1,182 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QtWidgets>
#include "addressbook.h"
AddressBook::AddressBook(QWidget *parent)
: QWidget(parent)
{
QLabel *nameLabel = new QLabel(tr("Name:"));
nameLine = new QLineEdit;
nameLine->setReadOnly(true);
QLabel *addressLabel = new QLabel(tr("Address:"));
addressText = new QTextEdit;
addressText->setReadOnly(true);
addButton = new QPushButton(tr("&Add"));
addButton->show();
submitButton = new QPushButton(tr("&Submit"));
submitButton->hide();
cancelButton = new QPushButton(tr("&Cancel"));
cancelButton->hide();
//! [navigation pushbuttons]
nextButton = new QPushButton(tr("&Next"));
nextButton->setEnabled(false);
previousButton = new QPushButton(tr("&Previous"));
previousButton->setEnabled(false);
//! [navigation pushbuttons]
connect(addButton, &QPushButton::clicked,
this, &AddressBook::addContact);
connect(submitButton, &QPushButton::clicked,
this, &AddressBook::submitContact);
connect(cancelButton, &QPushButton::clicked,
this, &AddressBook::cancel);
//! [connecting navigation signals]
connect(nextButton, &QPushButton::clicked,
this, &AddressBook::next);
connect(previousButton, &QPushButton::clicked,
this, &AddressBook::previous);
//! [connecting navigation signals]
QVBoxLayout *buttonLayout1 = new QVBoxLayout;
buttonLayout1->addWidget(addButton, Qt::AlignTop);
buttonLayout1->addWidget(submitButton);
buttonLayout1->addWidget(cancelButton);
buttonLayout1->addStretch();
//! [navigation layout]
QHBoxLayout *buttonLayout2 = new QHBoxLayout;
buttonLayout2->addWidget(previousButton);
buttonLayout2->addWidget(nextButton);
//! [ navigation layout]
QGridLayout *mainLayout = new QGridLayout;
mainLayout->addWidget(nameLabel, 0, 0);
mainLayout->addWidget(nameLine, 0, 1);
mainLayout->addWidget(addressLabel, 1, 0, Qt::AlignTop);
mainLayout->addWidget(addressText, 1, 1);
mainLayout->addLayout(buttonLayout1, 1, 2);
//! [adding navigation layout]
mainLayout->addLayout(buttonLayout2, 2, 1);
//! [adding navigation layout]
setLayout(mainLayout);
setWindowTitle(tr("Simple Address Book"));
}
void AddressBook::addContact()
{
oldName = nameLine->text();
oldAddress = addressText->toPlainText();
nameLine->clear();
addressText->clear();
nameLine->setReadOnly(false);
nameLine->setFocus(Qt::OtherFocusReason);
addressText->setReadOnly(false);
addButton->setEnabled(false);
//! [disabling navigation]
nextButton->setEnabled(false);
previousButton->setEnabled(false);
//! [disabling navigation]
submitButton->show();
cancelButton->show();
}
void AddressBook::submitContact()
{
QString name = nameLine->text();
QString address = addressText->toPlainText();
if (name.isEmpty() || address.isEmpty()) {
QMessageBox::information(this, tr("Empty Field"),
tr("Please enter a name and address."));
return;
}
if (!contacts.contains(name)) {
contacts.insert(name, address);
QMessageBox::information(this, tr("Add Successful"),
tr("\"%1\" has been added to your address book.").arg(name));
} else {
QMessageBox::information(this, tr("Add Unsuccessful"),
tr("Sorry, \"%1\" is already in your address book.").arg(name));
}
if (contacts.isEmpty()) {
nameLine->clear();
addressText->clear();
}
nameLine->setReadOnly(true);
addressText->setReadOnly(true);
addButton->setEnabled(true);
//! [enabling navigation]
int number = contacts.size();
nextButton->setEnabled(number > 1);
previousButton->setEnabled(number > 1);
//! [enabling navigation]
submitButton->hide();
cancelButton->hide();
}
void AddressBook::cancel()
{
nameLine->setText(oldName);
addressText->setText(oldAddress);
if (contacts.isEmpty()) {
nameLine->clear();
addressText->clear();
}
nameLine->setReadOnly(true);
addressText->setReadOnly(true);
addButton->setEnabled(true);
int number = contacts.size();
nextButton->setEnabled(number > 1);
previousButton->setEnabled(number > 1);
submitButton->hide();
cancelButton->hide();
}
//! [next() function]
void AddressBook::next()
{
QString name = nameLine->text();
QMap<QString, QString>::iterator i = contacts.find(name);
if (i != contacts.end())
i++;
if (i == contacts.end())
i = contacts.begin();
nameLine->setText(i.key());
addressText->setText(i.value());
}
//! [next() function]
//! [previous() function]
void AddressBook::previous()
{
QString name = nameLine->text();
QMap<QString, QString>::iterator i = contacts.find(name);
if (i == contacts.end()){
nameLine->clear();
addressText->clear();
return;
}
if (i == contacts.begin())
i = contacts.end();
i--;
nameLine->setText(i.key());
addressText->setText(i.value());
}
//! [previous() function]

View File

@ -0,0 +1,49 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef ADDRESSBOOK_H
#define ADDRESSBOOK_H
#include <QWidget>
#include <QMap>
QT_BEGIN_NAMESPACE
class QLabel;
class QLineEdit;
class QPushButton;
class QTextEdit;
QT_END_NAMESPACE
class AddressBook : public QWidget
{
Q_OBJECT
public:
AddressBook(QWidget *parent = nullptr);
public slots:
void addContact();
void submitContact();
void cancel();
//! [navigation functions]
void next();
void previous();
//! [navigation functions]
private:
QPushButton *addButton;
QPushButton *submitButton;
QPushButton *cancelButton;
//! [navigation pushbuttons]
QPushButton *nextButton;
QPushButton *previousButton;
//! [navigation pushbuttons]
QLineEdit *nameLine;
QTextEdit *addressText;
QMap<QString, QString> contacts;
QString oldName;
QString oldAddress;
};
#endif

View File

@ -0,0 +1,15 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QtWidgets>
#include "addressbook.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
AddressBook addressBook;
addressBook.show();
return app.exec();
}

View File

@ -0,0 +1,11 @@
QT += widgets
SOURCES = addressbook.cpp \
main.cpp
HEADERS = addressbook.h
QMAKE_PROJECT_NAME = ab_part3
# install
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/tutorials/addressbook/part3
INSTALLS += target

View File

@ -0,0 +1,37 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(part4 LANGUAGES CXX)
if(NOT DEFINED INSTALL_EXAMPLESDIR)
set(INSTALL_EXAMPLESDIR "examples")
endif()
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/tutorials/addressbook/part4")
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
qt_standard_project_setup()
qt_add_executable(part4
addressbook.cpp addressbook.h
main.cpp
)
set_target_properties(part4 PROPERTIES
WIN32_EXECUTABLE TRUE
MACOSX_BUNDLE TRUE
)
target_link_libraries(part4 PRIVATE
Qt6::Core
Qt6::Gui
Qt6::Widgets
)
install(TARGETS part4
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
)

View File

@ -0,0 +1,258 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QtWidgets>
#include "addressbook.h"
AddressBook::AddressBook(QWidget *parent)
: QWidget(parent)
{
QLabel *nameLabel = new QLabel(tr("Name:"));
nameLine = new QLineEdit;
nameLine->setReadOnly(true);
QLabel *addressLabel = new QLabel(tr("Address:"));
addressText = new QTextEdit;
addressText->setReadOnly(true);
addButton = new QPushButton(tr("&Add"));
//! [edit and remove buttons]
editButton = new QPushButton(tr("&Edit"));
editButton->setEnabled(false);
removeButton = new QPushButton(tr("&Remove"));
removeButton->setEnabled(false);
//! [edit and remove buttons]
submitButton = new QPushButton(tr("&Submit"));
submitButton->hide();
cancelButton = new QPushButton(tr("&Cancel"));
cancelButton->hide();
nextButton = new QPushButton(tr("&Next"));
nextButton->setEnabled(false);
previousButton = new QPushButton(tr("&Previous"));
previousButton->setEnabled(false);
connect(addButton, &QPushButton::clicked,
this, &AddressBook::addContact);
connect(submitButton, &QPushButton::clicked,
this, &AddressBook::submitContact);
//! [connecting edit and remove]
connect(editButton, &QPushButton::clicked,
this, &AddressBook::editContact);
connect(removeButton, &QPushButton::clicked,
this, &AddressBook::removeContact);
//! [connecting edit and remove]
connect(cancelButton, &QPushButton::clicked,
this, &AddressBook::cancel);
connect(nextButton, &QPushButton::clicked,
this, &AddressBook::next);
connect(previousButton, &QPushButton::clicked,
this, &AddressBook::previous);
QVBoxLayout *buttonLayout1 = new QVBoxLayout;
buttonLayout1->addWidget(addButton);
//! [adding edit and remove to the layout]
buttonLayout1->addWidget(editButton);
buttonLayout1->addWidget(removeButton);
//! [adding edit and remove to the layout]
buttonLayout1->addWidget(submitButton);
buttonLayout1->addWidget(cancelButton);
buttonLayout1->addStretch();
QHBoxLayout *buttonLayout2 = new QHBoxLayout;
buttonLayout2->addWidget(previousButton);
buttonLayout2->addWidget(nextButton);
QGridLayout *mainLayout = new QGridLayout;
mainLayout->addWidget(nameLabel, 0, 0);
mainLayout->addWidget(nameLine, 0, 1);
mainLayout->addWidget(addressLabel, 1, 0, Qt::AlignTop);
mainLayout->addWidget(addressText, 1, 1);
mainLayout->addLayout(buttonLayout1, 1, 2);
mainLayout->addLayout(buttonLayout2, 2, 1);
setLayout(mainLayout);
setWindowTitle(tr("Simple Address Book"));
}
void AddressBook::addContact()
{
oldName = nameLine->text();
oldAddress = addressText->toPlainText();
nameLine->clear();
addressText->clear();
updateInterface(AddingMode);
}
//! [editContact() function]
void AddressBook::editContact()
{
oldName = nameLine->text();
oldAddress = addressText->toPlainText();
updateInterface(EditingMode);
}
//! [editContact() function]
//! [submitContact() function beginning]
void AddressBook::submitContact()
{
//! [submitContact() function beginning]
QString name = nameLine->text();
QString address = addressText->toPlainText();
if (name.isEmpty() || address.isEmpty()) {
QMessageBox::information(this, tr("Empty Field"),
tr("Please enter a name and address."));
return;
}
//! [submitContact() function part1]
if (currentMode == AddingMode) {
if (!contacts.contains(name)) {
contacts.insert(name, address);
QMessageBox::information(this, tr("Add Successful"),
tr("\"%1\" has been added to your address book.").arg(name));
} else {
QMessageBox::information(this, tr("Add Unsuccessful"),
tr("Sorry, \"%1\" is already in your address book.").arg(name));
}
//! [submitContact() function part1]
//! [submitContact() function part2]
} else if (currentMode == EditingMode) {
if (oldName != name) {
if (!contacts.contains(name)) {
QMessageBox::information(this, tr("Edit Successful"),
tr("\"%1\" has been edited in your address book.").arg(oldName));
contacts.remove(oldName);
contacts.insert(name, address);
} else {
QMessageBox::information(this, tr("Edit Unsuccessful"),
tr("Sorry, \"%1\" is already in your address book.").arg(name));
}
} else if (oldAddress != address) {
QMessageBox::information(this, tr("Edit Successful"),
tr("\"%1\" has been edited in your address book.").arg(name));
contacts[name] = address;
}
}
updateInterface(NavigationMode);
}
//! [submitContact() function part2]
void AddressBook::cancel()
{
nameLine->setText(oldName);
addressText->setText(oldAddress);
updateInterface(NavigationMode);
}
//! [removeContact() function]
void AddressBook::removeContact()
{
QString name = nameLine->text();
QString address = addressText->toPlainText();
if (contacts.contains(name)) {
int button = QMessageBox::question(this,
tr("Confirm Remove"),
tr("Are you sure you want to remove \"%1\"?").arg(name),
QMessageBox::Yes | QMessageBox::No);
if (button == QMessageBox::Yes) {
previous();
contacts.remove(name);
QMessageBox::information(this, tr("Remove Successful"),
tr("\"%1\" has been removed from your address book.").arg(name));
}
}
updateInterface(NavigationMode);
}
//! [removeContact() function]
void AddressBook::next()
{
QString name = nameLine->text();
QMap<QString, QString>::iterator i = contacts.find(name);
if (i != contacts.end())
i++;
if (i == contacts.end())
i = contacts.begin();
nameLine->setText(i.key());
addressText->setText(i.value());
}
void AddressBook::previous()
{
QString name = nameLine->text();
QMap<QString, QString>::iterator i = contacts.find(name);
if (i == contacts.end()) {
nameLine->clear();
addressText->clear();
return;
}
if (i == contacts.begin())
i = contacts.end();
i--;
nameLine->setText(i.key());
addressText->setText(i.value());
}
//! [update interface() part 1]
void AddressBook::updateInterface(Mode mode)
{
currentMode = mode;
switch (currentMode) {
case AddingMode:
case EditingMode:
nameLine->setReadOnly(false);
nameLine->setFocus(Qt::OtherFocusReason);
addressText->setReadOnly(false);
addButton->setEnabled(false);
editButton->setEnabled(false);
removeButton->setEnabled(false);
nextButton->setEnabled(false);
previousButton->setEnabled(false);
submitButton->show();
cancelButton->show();
break;
//! [update interface() part 1]
//! [update interface() part 2]
case NavigationMode:
if (contacts.isEmpty()) {
nameLine->clear();
addressText->clear();
}
nameLine->setReadOnly(true);
addressText->setReadOnly(true);
addButton->setEnabled(true);
int number = contacts.size();
editButton->setEnabled(number >= 1);
removeButton->setEnabled(number >= 1);
nextButton->setEnabled(number > 1);
previousButton->setEnabled(number >1 );
submitButton->hide();
cancelButton->hide();
break;
}
}
//! [update interface() part 2]

View File

@ -0,0 +1,62 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef ADDRESSBOOK_H
#define ADDRESSBOOK_H
#include <QWidget>
#include <QMap>
QT_BEGIN_NAMESPACE
class QPushButton;
class QLabel;
class QLineEdit;
class QTextEdit;
QT_END_NAMESPACE
class AddressBook : public QWidget
{
Q_OBJECT
public:
AddressBook(QWidget *parent = nullptr);
//! [Mode enum]
enum Mode { NavigationMode, AddingMode, EditingMode };
//! [Mode enum]
public slots:
void addContact();
void submitContact();
void cancel();
//! [edit and remove slots]
void editContact();
void removeContact();
//! [edit and remove slots]
void next();
void previous();
private:
//! [updateInterface() declaration]
void updateInterface(Mode mode);
//! [updateInterface() declaration]
QPushButton *addButton;
//! [buttons declaration]
QPushButton *editButton;
QPushButton *removeButton;
//! [buttons declaration]
QPushButton *submitButton;
QPushButton *cancelButton;
QPushButton *nextButton;
QPushButton *previousButton;
QLineEdit *nameLine;
QTextEdit *addressText;
QMap<QString, QString> contacts;
QString oldName;
QString oldAddress;
//! [mode declaration]
Mode currentMode;
//! [mode declaration]
};
#endif

View File

@ -0,0 +1,15 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QtWidgets>
#include "addressbook.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
AddressBook addressBook;
addressBook.show();
return app.exec();
}

View File

@ -0,0 +1,11 @@
QT += widgets
SOURCES = addressbook.cpp \
main.cpp
HEADERS = addressbook.h
QMAKE_PROJECT_NAME = ab_part4
# install
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/tutorials/addressbook/part4
INSTALLS += target

View File

@ -0,0 +1,38 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(part5 LANGUAGES CXX)
if(NOT DEFINED INSTALL_EXAMPLESDIR)
set(INSTALL_EXAMPLESDIR "examples")
endif()
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/tutorials/addressbook/part5")
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
qt_standard_project_setup()
qt_add_executable(part5
addressbook.cpp addressbook.h
finddialog.cpp finddialog.h
main.cpp
)
set_target_properties(part5 PROPERTIES
WIN32_EXECUTABLE TRUE
MACOSX_BUNDLE TRUE
)
target_link_libraries(part5 PRIVATE
Qt6::Core
Qt6::Gui
Qt6::Widgets
)
install(TARGETS part5
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
)

View File

@ -0,0 +1,283 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QtWidgets>
#include "addressbook.h"
AddressBook::AddressBook(QWidget *parent)
: QWidget(parent)
{
QLabel *nameLabel = new QLabel(tr("Name:"));
nameLine = new QLineEdit;
nameLine->setReadOnly(true);
QLabel *addressLabel = new QLabel(tr("Address:"));
addressText = new QTextEdit;
addressText->setReadOnly(true);
addButton = new QPushButton(tr("&Add"));
editButton = new QPushButton(tr("&Edit"));
editButton->setEnabled(false);
removeButton = new QPushButton(tr("&Remove"));
removeButton->setEnabled(false);
//! [instantiating findButton]
findButton = new QPushButton(tr("&Find"));
findButton->setEnabled(false);
//! [instantiating findButton]
submitButton = new QPushButton(tr("&Submit"));
submitButton->hide();
cancelButton = new QPushButton(tr("&Cancel"));
cancelButton->hide();
nextButton = new QPushButton(tr("&Next"));
nextButton->setEnabled(false);
previousButton = new QPushButton(tr("&Previous"));
previousButton->setEnabled(false);
//! [instantiating FindDialog]
dialog = new FindDialog(this);
//! [instantiating FindDialog]
connect(addButton, &QPushButton::clicked,
this, &AddressBook::addContact);
connect(submitButton, &QPushButton::clicked,
this, &AddressBook::submitContact);
connect(editButton, &QPushButton::clicked,
this, &AddressBook::editContact);
connect(removeButton, &QPushButton::clicked,
this, &AddressBook::removeContact);
connect(cancelButton, &QPushButton::clicked,
this, &AddressBook::cancel);
//! [signals and slots for find]
connect(findButton, &QPushButton::clicked,
this, &AddressBook::findContact);
//! [signals and slots for find]
connect(nextButton, &QPushButton::clicked,
this, &AddressBook::next);
connect(previousButton, &QPushButton::clicked,
this, &AddressBook::previous);
QVBoxLayout *buttonLayout1 = new QVBoxLayout;
buttonLayout1->addWidget(addButton);
buttonLayout1->addWidget(editButton);
buttonLayout1->addWidget(removeButton);
//! [adding findButton to layout]
buttonLayout1->addWidget(findButton);
//! [adding findButton to layout]
buttonLayout1->addWidget(submitButton);
buttonLayout1->addWidget(cancelButton);
buttonLayout1->addStretch();
QHBoxLayout *buttonLayout2 = new QHBoxLayout;
buttonLayout2->addWidget(previousButton);
buttonLayout2->addWidget(nextButton);
QGridLayout *mainLayout = new QGridLayout;
mainLayout->addWidget(nameLabel, 0, 0);
mainLayout->addWidget(nameLine, 0, 1);
mainLayout->addWidget(addressLabel, 1, 0, Qt::AlignTop);
mainLayout->addWidget(addressText, 1, 1);
mainLayout->addLayout(buttonLayout1, 1, 2);
mainLayout->addLayout(buttonLayout2, 2, 1);
setLayout(mainLayout);
setWindowTitle(tr("Simple Address Book"));
}
void AddressBook::addContact()
{
oldName = nameLine->text();
oldAddress = addressText->toPlainText();
nameLine->clear();
addressText->clear();
updateInterface(AddingMode);
}
void AddressBook::editContact()
{
oldName = nameLine->text();
oldAddress = addressText->toPlainText();
updateInterface(EditingMode);
}
void AddressBook::submitContact()
{
QString name = nameLine->text();
QString address = addressText->toPlainText();
if (name.isEmpty() || address.isEmpty()) {
QMessageBox::information(this, tr("Empty Field"),
tr("Please enter a name and address."));
return;
}
if (currentMode == AddingMode) {
if (!contacts.contains(name)) {
contacts.insert(name, address);
QMessageBox::information(this, tr("Add Successful"),
tr("\"%1\" has been added to your address book.").arg(name));
} else {
QMessageBox::information(this, tr("Add Unsuccessful"),
tr("Sorry, \"%1\" is already in your address book.").arg(name));
}
} else if (currentMode == EditingMode) {
if (oldName != name) {
if (!contacts.contains(name)) {
QMessageBox::information(this, tr("Edit Successful"),
tr("\"%1\" has been edited in your address book.").arg(oldName));
contacts.remove(oldName);
contacts.insert(name, address);
} else {
QMessageBox::information(this, tr("Edit Unsuccessful"),
tr("Sorry, \"%1\" is already in your address book.").arg(name));
}
} else if (oldAddress != address) {
QMessageBox::information(this, tr("Edit Successful"),
tr("\"%1\" has been edited in your address book.").arg(name));
contacts[name] = address;
}
}
updateInterface(NavigationMode);
}
void AddressBook::cancel()
{
nameLine->setText(oldName);
addressText->setText(oldAddress);
updateInterface(NavigationMode);
}
void AddressBook::removeContact()
{
QString name = nameLine->text();
QString address = addressText->toPlainText();
if (contacts.contains(name)) {
int button = QMessageBox::question(this,
tr("Confirm Remove"),
tr("Are you sure you want to remove \"%1\"?").arg(name),
QMessageBox::Yes | QMessageBox::No);
if (button == QMessageBox::Yes) {
previous();
contacts.remove(name);
QMessageBox::information(this, tr("Remove Successful"),
tr("\"%1\" has been removed from your address book.").arg(name));
}
}
updateInterface(NavigationMode);
}
void AddressBook::next()
{
QString name = nameLine->text();
QMap<QString, QString>::iterator i = contacts.find(name);
if (i != contacts.end())
i++;
if (i == contacts.end())
i = contacts.begin();
nameLine->setText(i.key());
addressText->setText(i.value());
}
void AddressBook::previous()
{
QString name = nameLine->text();
QMap<QString, QString>::iterator i = contacts.find(name);
if (i == contacts.end()) {
nameLine->clear();
addressText->clear();
return;
}
if (i == contacts.begin())
i = contacts.end();
i--;
nameLine->setText(i.key());
addressText->setText(i.value());
}
//! [findContact() function]
void AddressBook::findContact()
{
dialog->show();
if (dialog->exec() == QDialog::Accepted) {
QString contactName = dialog->getFindText();
if (contacts.contains(contactName)) {
nameLine->setText(contactName);
addressText->setText(contacts.value(contactName));
} else {
QMessageBox::information(this, tr("Contact Not Found"),
tr("Sorry, \"%1\" is not in your address book.").arg(contactName));
return;
}
}
updateInterface(NavigationMode);
}
//! [findContact() function]
void AddressBook::updateInterface(Mode mode)
{
currentMode = mode;
switch (currentMode) {
case AddingMode:
case EditingMode:
nameLine->setReadOnly(false);
nameLine->setFocus(Qt::OtherFocusReason);
addressText->setReadOnly(false);
addButton->setEnabled(false);
editButton->setEnabled(false);
removeButton->setEnabled(false);
nextButton->setEnabled(false);
previousButton->setEnabled(false);
submitButton->show();
cancelButton->show();
break;
case NavigationMode:
if (contacts.isEmpty()) {
nameLine->clear();
addressText->clear();
}
nameLine->setReadOnly(true);
addressText->setReadOnly(true);
addButton->setEnabled(true);
int number = contacts.size();
editButton->setEnabled(number >= 1);
removeButton->setEnabled(number >= 1);
findButton->setEnabled(number > 2);
nextButton->setEnabled(number > 1);
previousButton->setEnabled(number > 1);
submitButton->hide();
cancelButton->hide();
break;
}
}

View File

@ -0,0 +1,65 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef ADDRESSBOOK_H
#define ADDRESSBOOK_H
#include <QWidget>
#include <QMap>
//! [include finddialog's header]
#include "finddialog.h"
//! [include finddialog's header]
QT_BEGIN_NAMESPACE
class QPushButton;
class QLabel;
class QLineEdit;
class QTextEdit;
QT_END_NAMESPACE
class AddressBook : public QWidget
{
Q_OBJECT
public:
AddressBook(QWidget *parent = nullptr);
enum Mode { NavigationMode, AddingMode, EditingMode };
public slots:
void addContact();
void editContact();
void submitContact();
void cancel();
void removeContact();
//! [findContact() declaration]
void findContact();
//! [findContact() declaration]
void next();
void previous();
private:
void updateInterface(Mode mode);
QPushButton *addButton;
QPushButton *editButton;
QPushButton *removeButton;
//! [findButton declaration]
QPushButton *findButton;
//! [findButton declaration]
QPushButton *submitButton;
QPushButton *cancelButton;
QPushButton *nextButton;
QPushButton *previousButton;
QLineEdit *nameLine;
QTextEdit *addressText;
QMap<QString, QString> contacts;
//! [FindDialog declaration]
FindDialog *dialog;
//! [FindDialog declaration]
QString oldName;
QString oldAddress;
Mode currentMode;
};
#endif

View File

@ -0,0 +1,51 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QtWidgets>
#include "finddialog.h"
//! [constructor]
FindDialog::FindDialog(QWidget *parent)
: QDialog(parent)
{
QLabel *findLabel = new QLabel(tr("Enter the name of a contact:"));
lineEdit = new QLineEdit;
findButton = new QPushButton(tr("&Find"));
findText = "";
QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(findLabel);
layout->addWidget(lineEdit);
layout->addWidget(findButton);
setLayout(layout);
setWindowTitle(tr("Find a Contact"));
connect(findButton, &QPushButton::clicked,
this, &FindDialog::findClicked);
connect(findButton, &QPushButton::clicked,
this, &FindDialog::accept);
}
//! [constructor]
//! [findClicked() function]
void FindDialog::findClicked()
{
QString text = lineEdit->text();
if (text.isEmpty()) {
QMessageBox::information(this, tr("Empty Field"),
tr("Please enter a name."));
return;
} else {
findText = text;
lineEdit->clear();
hide();
}
}
//! [findClicked() function]
//! [getFindText() function]
QString FindDialog::getFindText()
{
return findText;
}
//! [getFindText() function]

View File

@ -0,0 +1,31 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef FINDDIALOG_H
#define FINDDIALOG_H
//! [FindDialog header]
#include <QDialog>
QT_BEGIN_NAMESPACE
class QLineEdit;
class QPushButton;
QT_END_NAMESPACE
class FindDialog : public QDialog
{
Q_OBJECT
public:
FindDialog(QWidget *parent = nullptr);
QString getFindText();
public slots:
void findClicked();
private:
QPushButton *findButton;
QLineEdit *lineEdit;
QString findText;
};
//! [FindDialog header]
#endif

View File

@ -0,0 +1,15 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QtWidgets>
#include "addressbook.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
AddressBook addressBook;
addressBook.show();
return app.exec();
}

View File

@ -0,0 +1,13 @@
QT += widgets
SOURCES = addressbook.cpp \
finddialog.cpp \
main.cpp
HEADERS = addressbook.h \
finddialog.h
QMAKE_PROJECT_NAME = ab_part5
# install
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/tutorials/addressbook/part5
INSTALLS += target

View File

@ -0,0 +1,38 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(part6 LANGUAGES CXX)
if(NOT DEFINED INSTALL_EXAMPLESDIR)
set(INSTALL_EXAMPLESDIR "examples")
endif()
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/tutorials/addressbook/part6")
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
qt_standard_project_setup()
qt_add_executable(part6
addressbook.cpp addressbook.h
finddialog.cpp finddialog.h
main.cpp
)
set_target_properties(part6 PROPERTIES
WIN32_EXECUTABLE TRUE
MACOSX_BUNDLE TRUE
)
target_link_libraries(part6 PRIVATE
Qt6::Core
Qt6::Gui
Qt6::Widgets
)
install(TARGETS part6
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
)

View File

@ -0,0 +1,366 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QtWidgets>
#include "addressbook.h"
AddressBook::AddressBook(QWidget *parent)
: QWidget(parent)
{
QLabel *nameLabel = new QLabel(tr("Name:"));
nameLine = new QLineEdit;
nameLine->setReadOnly(true);
QLabel *addressLabel = new QLabel(tr("Address:"));
addressText = new QTextEdit;
addressText->setReadOnly(true);
addButton = new QPushButton(tr("&Add"));
editButton = new QPushButton(tr("&Edit"));
editButton->setEnabled(false);
removeButton = new QPushButton(tr("&Remove"));
removeButton->setEnabled(false);
findButton = new QPushButton(tr("&Find"));
findButton->setEnabled(false);
submitButton = new QPushButton(tr("&Submit"));
submitButton->hide();
cancelButton = new QPushButton(tr("&Cancel"));
cancelButton->hide();
nextButton = new QPushButton(tr("&Next"));
nextButton->setEnabled(false);
previousButton = new QPushButton(tr("&Previous"));
previousButton->setEnabled(false);
loadButton = new QPushButton(tr("&Load..."));
//! [tooltip 1]
loadButton->setToolTip(tr("Load contacts from a file"));
//! [tooltip 1]
saveButton = new QPushButton(tr("&Save..."));
//! [tooltip 2]
saveButton->setToolTip(tr("Save contacts to a file"));
//! [tooltip 2]
saveButton->setEnabled(false);
dialog = new FindDialog(this);
connect(addButton, &QPushButton::clicked,
this, &AddressBook::addContact);
connect(submitButton, &QPushButton::clicked,
this, &AddressBook::submitContact);
connect(editButton, &QPushButton::clicked,
this, &AddressBook::editContact);
connect(removeButton, &QPushButton::clicked,
this, &AddressBook::removeContact);
connect(cancelButton, &QPushButton::clicked,
this, &AddressBook::cancel);
connect(findButton, &QPushButton::clicked,
this, &AddressBook::findContact);
connect(nextButton, &QPushButton::clicked,
this, &AddressBook::next);
connect(previousButton, &QPushButton::clicked,
this, &AddressBook::previous);
connect(loadButton, &QPushButton::clicked,
this, &AddressBook::loadFromFile);
connect(saveButton, &QPushButton::clicked,
this, &AddressBook::saveToFile);
QVBoxLayout *buttonLayout1 = new QVBoxLayout;
buttonLayout1->addWidget(addButton);
buttonLayout1->addWidget(editButton);
buttonLayout1->addWidget(removeButton);
buttonLayout1->addWidget(findButton);
buttonLayout1->addWidget(submitButton);
buttonLayout1->addWidget(cancelButton);
buttonLayout1->addWidget(loadButton);
buttonLayout1->addWidget(saveButton);
buttonLayout1->addStretch();
QHBoxLayout *buttonLayout2 = new QHBoxLayout;
buttonLayout2->addWidget(previousButton);
buttonLayout2->addWidget(nextButton);
QGridLayout *mainLayout = new QGridLayout;
mainLayout->addWidget(nameLabel, 0, 0);
mainLayout->addWidget(nameLine, 0, 1);
mainLayout->addWidget(addressLabel, 1, 0, Qt::AlignTop);
mainLayout->addWidget(addressText, 1, 1);
mainLayout->addLayout(buttonLayout1, 1, 2);
mainLayout->addLayout(buttonLayout2, 2, 1);
setLayout(mainLayout);
setWindowTitle(tr("Simple Address Book"));
}
void AddressBook::addContact()
{
oldName = nameLine->text();
oldAddress = addressText->toPlainText();
nameLine->clear();
addressText->clear();
updateInterface(AddingMode);
}
void AddressBook::editContact()
{
oldName = nameLine->text();
oldAddress = addressText->toPlainText();
updateInterface(EditingMode);
}
void AddressBook::submitContact()
{
QString name = nameLine->text();
QString address = addressText->toPlainText();
if (name.isEmpty() || address.isEmpty()) {
QMessageBox::information(this, tr("Empty Field"),
tr("Please enter a name and address."));
return;
}
if (currentMode == AddingMode) {
if (!contacts.contains(name)) {
contacts.insert(name, address);
QMessageBox::information(this, tr("Add Successful"),
tr("\"%1\" has been added to your address book.").arg(name));
} else {
QMessageBox::information(this, tr("Add Unsuccessful"),
tr("Sorry, \"%1\" is already in your address book.").arg(name));
}
} else if (currentMode == EditingMode) {
if (oldName != name) {
if (!contacts.contains(name)) {
QMessageBox::information(this, tr("Edit Successful"),
tr("\"%1\" has been edited in your address book.").arg(oldName));
contacts.remove(oldName);
contacts.insert(name, address);
} else {
QMessageBox::information(this, tr("Edit Unsuccessful"),
tr("Sorry, \"%1\" is already in your address book.").arg(name));
}
} else if (oldAddress != address) {
QMessageBox::information(this, tr("Edit Successful"),
tr("\"%1\" has been edited in your address book.").arg(name));
contacts[name] = address;
}
}
updateInterface(NavigationMode);
}
void AddressBook::cancel()
{
nameLine->setText(oldName);
addressText->setText(oldAddress);
updateInterface(NavigationMode);
}
void AddressBook::removeContact()
{
QString name = nameLine->text();
QString address = addressText->toPlainText();
if (contacts.contains(name)) {
int button = QMessageBox::question(this,
tr("Confirm Remove"),
tr("Are you sure you want to remove \"%1\"?").arg(name),
QMessageBox::Yes | QMessageBox::No);
if (button == QMessageBox::Yes) {
previous();
contacts.remove(name);
QMessageBox::information(this, tr("Remove Successful"),
tr("\"%1\" has been removed from your address book.").arg(name));
}
}
updateInterface(NavigationMode);
}
void AddressBook::next()
{
QString name = nameLine->text();
QMap<QString, QString>::iterator i = contacts.find(name);
if (i != contacts.end())
i++;
if (i == contacts.end())
i = contacts.begin();
nameLine->setText(i.key());
addressText->setText(i.value());
}
void AddressBook::previous()
{
QString name = nameLine->text();
QMap<QString, QString>::iterator i = contacts.find(name);
if (i == contacts.end()) {
nameLine->clear();
addressText->clear();
return;
}
if (i == contacts.begin())
i = contacts.end();
i--;
nameLine->setText(i.key());
addressText->setText(i.value());
}
void AddressBook::findContact()
{
dialog->show();
if (dialog->exec() == 1) {
QString contactName = dialog->getFindText();
if (contacts.contains(contactName)) {
nameLine->setText(contactName);
addressText->setText(contacts.value(contactName));
} else {
QMessageBox::information(this, tr("Contact Not Found"),
tr("Sorry, \"%1\" is not in your address book.").arg(contactName));
return;
}
}
updateInterface(NavigationMode);
}
void AddressBook::updateInterface(Mode mode)
{
currentMode = mode;
switch (currentMode) {
case AddingMode:
case EditingMode:
nameLine->setReadOnly(false);
nameLine->setFocus(Qt::OtherFocusReason);
addressText->setReadOnly(false);
addButton->setEnabled(false);
editButton->setEnabled(false);
removeButton->setEnabled(false);
nextButton->setEnabled(false);
previousButton->setEnabled(false);
submitButton->show();
cancelButton->show();
loadButton->setEnabled(false);
saveButton->setEnabled(false);
break;
case NavigationMode:
if (contacts.isEmpty()) {
nameLine->clear();
addressText->clear();
}
nameLine->setReadOnly(true);
addressText->setReadOnly(true);
addButton->setEnabled(true);
int number = contacts.size();
editButton->setEnabled(number >= 1);
removeButton->setEnabled(number >= 1);
findButton->setEnabled(number > 2);
nextButton->setEnabled(number > 1);
previousButton->setEnabled(number > 1);
submitButton->hide();
cancelButton->hide();
loadButton->setEnabled(true);
saveButton->setEnabled(number >= 1);
break;
}
}
//! [saveToFile() function part1]
void AddressBook::saveToFile()
{
QString fileName = QFileDialog::getSaveFileName(this,
tr("Save Address Book"), "",
tr("Address Book (*.abk);;All Files (*)"));
//! [saveToFile() function part1]
//! [saveToFile() function part2]
if (fileName.isEmpty())
return;
else {
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly)) {
QMessageBox::information(this, tr("Unable to open file"),
file.errorString());
return;
}
//! [saveToFile() function part2]
//! [saveToFile() function part3]
QDataStream out(&file);
out.setVersion(QDataStream::Qt_4_5);
out << contacts;
}
}
//! [saveToFile() function part3]
//! [loadFromFile() function part1]
void AddressBook::loadFromFile()
{
QString fileName = QFileDialog::getOpenFileName(this,
tr("Open Address Book"), "",
tr("Address Book (*.abk);;All Files (*)"));
//! [loadFromFile() function part1]
//! [loadFromFile() function part2]
if (fileName.isEmpty())
return;
else {
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly)) {
QMessageBox::information(this, tr("Unable to open file"),
file.errorString());
return;
}
QDataStream in(&file);
in.setVersion(QDataStream::Qt_4_5);
contacts.clear(); // clear existing contacts
in >> contacts;
//! [loadFromFile() function part2]
//! [loadFromFile() function part3]
if (contacts.isEmpty()) {
QMessageBox::information(this, tr("No contacts in file"),
tr("The file you are attempting to open contains no contacts."));
} else {
QMap<QString, QString>::iterator i = contacts.begin();
nameLine->setText(i.key());
addressText->setText(i.value());
}
}
updateInterface(NavigationMode);
}
//! [loadFromFile() function part3]

View File

@ -0,0 +1,66 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef ADDRESSBOOK_H
#define ADDRESSBOOK_H
#include <QWidget>
#include <QMap>
#include "finddialog.h"
QT_BEGIN_NAMESPACE
class QPushButton;
class QLabel;
class QLineEdit;
class QTextEdit;
QT_END_NAMESPACE
class AddressBook : public QWidget
{
Q_OBJECT
public:
AddressBook(QWidget *parent = nullptr);
enum Mode { NavigationMode, AddingMode, EditingMode };
public slots:
void addContact();
void editContact();
void submitContact();
void cancel();
void removeContact();
void findContact();
void next();
void previous();
//! [save and load functions declaration]
void saveToFile();
void loadFromFile();
//! [save and load functions declaration]
private:
void updateInterface(Mode mode);
QPushButton *addButton;
QPushButton *editButton;
QPushButton *removeButton;
QPushButton *findButton;
QPushButton *submitButton;
QPushButton *cancelButton;
QPushButton *nextButton;
QPushButton *previousButton;
//! [save and load buttons declaration]
QPushButton *loadButton;
QPushButton *saveButton;
//! [save and load buttons declaration]
QLineEdit *nameLine;
QTextEdit *addressText;
QMap<QString, QString> contacts;
FindDialog *dialog;
QString oldName;
QString oldAddress;
Mode currentMode;
};
#endif

View File

@ -0,0 +1,47 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QtWidgets>
#include "finddialog.h"
FindDialog::FindDialog(QWidget *parent)
: QDialog(parent)
{
QLabel *findLabel = new QLabel(tr("Enter the name of a contact:"));
lineEdit = new QLineEdit;
findButton = new QPushButton(tr("&Find"));
findText = "";
QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(findLabel);
layout->addWidget(lineEdit);
layout->addWidget(findButton);
setLayout(layout);
setWindowTitle(tr("Find a Contact"));
connect(findButton, &QPushButton::clicked,
this, &FindDialog::findClicked);
connect(findButton, &QPushButton::clicked,
this, &FindDialog::accept);
}
void FindDialog::findClicked()
{
QString text = lineEdit->text();
if (text.isEmpty()) {
QMessageBox::information(this, tr("Empty Field"),
tr("Please enter a name."));
return;
} else {
findText = text;
lineEdit->clear();
hide();
}
}
QString FindDialog::getFindText()
{
return findText;
}

View File

@ -0,0 +1,31 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef FINDDIALOG_H
#define FINDDIALOG_H
#include <QDialog>
QT_BEGIN_NAMESPACE
class QLineEdit;
class QPushButton;
QT_END_NAMESPACE
class FindDialog : public QDialog
{
Q_OBJECT
public:
FindDialog(QWidget *parent = nullptr);
QString getFindText();
public slots:
void findClicked();
private:
QPushButton *findButton;
QLineEdit *lineEdit;
QString findText;
};
#endif

View File

@ -0,0 +1,15 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QtWidgets>
#include "addressbook.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
AddressBook addressBook;
addressBook.show();
return app.exec();
}

View File

@ -0,0 +1,14 @@
QT += widgets
requires(qtConfig(filedialog))
SOURCES = addressbook.cpp \
finddialog.cpp \
main.cpp
HEADERS = addressbook.h \
finddialog.h
QMAKE_PROJECT_NAME = ab_part6
# install
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/tutorials/addressbook/part6
INSTALLS += target

View File

@ -0,0 +1,38 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(part7 LANGUAGES CXX)
if(NOT DEFINED INSTALL_EXAMPLESDIR)
set(INSTALL_EXAMPLESDIR "examples")
endif()
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/tutorials/addressbook/part7")
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
qt_standard_project_setup()
qt_add_executable(part7
addressbook.cpp addressbook.h
finddialog.cpp finddialog.h
main.cpp
)
set_target_properties(part7 PROPERTIES
WIN32_EXECUTABLE TRUE
MACOSX_BUNDLE TRUE
)
target_link_libraries(part7 PRIVATE
Qt6::Core
Qt6::Gui
Qt6::Widgets
)
install(TARGETS part7
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
)

View File

@ -0,0 +1,419 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QtWidgets>
#include "addressbook.h"
AddressBook::AddressBook(QWidget *parent)
: QWidget(parent)
{
QLabel *nameLabel = new QLabel(tr("Name:"));
nameLine = new QLineEdit;
nameLine->setReadOnly(true);
QLabel *addressLabel = new QLabel(tr("Address:"));
addressText = new QTextEdit;
addressText->setReadOnly(true);
addButton = new QPushButton(tr("&Add"));
editButton = new QPushButton(tr("&Edit"));
editButton->setEnabled(false);
removeButton = new QPushButton(tr("&Remove"));
removeButton->setEnabled(false);
findButton = new QPushButton(tr("&Find"));
findButton->setEnabled(false);
submitButton = new QPushButton(tr("&Submit"));
submitButton->hide();
cancelButton = new QPushButton(tr("&Cancel"));
cancelButton->hide();
nextButton = new QPushButton(tr("&Next"));
nextButton->setEnabled(false);
previousButton = new QPushButton(tr("&Previous"));
previousButton->setEnabled(false);
loadButton = new QPushButton(tr("&Load..."));
loadButton->setToolTip(tr("Load contacts from a file"));
saveButton = new QPushButton(tr("&Save..."));
saveButton->setToolTip(tr("Save contacts to a file"));
saveButton->setEnabled(false);
exportButton = new QPushButton(tr("E&xport"));
exportButton->setToolTip(tr("Export as vCard"));
exportButton->setEnabled(false);
dialog = new FindDialog(this);
connect(addButton, &QPushButton::clicked,
this, &AddressBook::addContact);
connect(submitButton, &QPushButton::clicked,
this, &AddressBook::submitContact);
connect(editButton, &QPushButton::clicked,
this, &AddressBook::editContact);
connect(removeButton, &QPushButton::clicked,
this, &AddressBook::removeContact);
connect(cancelButton, &QPushButton::clicked,
this, &AddressBook::cancel);
connect(findButton, &QPushButton::clicked,
this, &AddressBook::findContact);
connect(nextButton, &QPushButton::clicked,
this, &AddressBook::next);
connect(previousButton, &QPushButton::clicked,
this, &AddressBook::previous);
connect(loadButton, &QPushButton::clicked,
this, &AddressBook::loadFromFile);
connect(saveButton, &QPushButton::clicked,
this, &AddressBook::saveToFile);
connect(exportButton, &QPushButton::clicked,
this, &AddressBook::exportAsVCard);
QVBoxLayout *buttonLayout1 = new QVBoxLayout;
buttonLayout1->addWidget(addButton);
buttonLayout1->addWidget(editButton);
buttonLayout1->addWidget(removeButton);
buttonLayout1->addWidget(findButton);
buttonLayout1->addWidget(submitButton);
buttonLayout1->addWidget(cancelButton);
buttonLayout1->addWidget(loadButton);
buttonLayout1->addWidget(saveButton);
buttonLayout1->addWidget(exportButton);
buttonLayout1->addStretch();
QHBoxLayout *buttonLayout2 = new QHBoxLayout;
buttonLayout2->addWidget(previousButton);
buttonLayout2->addWidget(nextButton);
QGridLayout *mainLayout = new QGridLayout;
mainLayout->addWidget(nameLabel, 0, 0);
mainLayout->addWidget(nameLine, 0, 1);
mainLayout->addWidget(addressLabel, 1, 0, Qt::AlignTop);
mainLayout->addWidget(addressText, 1, 1);
mainLayout->addLayout(buttonLayout1, 1, 2);
mainLayout->addLayout(buttonLayout2, 2, 1);
setLayout(mainLayout);
setWindowTitle(tr("Simple Address Book"));
}
void AddressBook::addContact()
{
oldName = nameLine->text();
oldAddress = addressText->toPlainText();
nameLine->clear();
addressText->clear();
updateInterface(AddingMode);
}
void AddressBook::editContact()
{
oldName = nameLine->text();
oldAddress = addressText->toPlainText();
updateInterface(EditingMode);
}
void AddressBook::submitContact()
{
QString name = nameLine->text();
QString address = addressText->toPlainText();
if (name.isEmpty() || address.isEmpty()) {
QMessageBox::information(this, tr("Empty Field"),
tr("Please enter a name and address."));
return;
}
if (currentMode == AddingMode) {
if (!contacts.contains(name)) {
contacts.insert(name, address);
QMessageBox::information(this, tr("Add Successful"),
tr("\"%1\" has been added to your address book.").arg(name));
} else {
QMessageBox::information(this, tr("Add Unsuccessful"),
tr("Sorry, \"%1\" is already in your address book.").arg(name));
}
} else if (currentMode == EditingMode) {
if (oldName != name) {
if (!contacts.contains(name)) {
QMessageBox::information(this, tr("Edit Successful"),
tr("\"%1\" has been edited in your address book.").arg(oldName));
contacts.remove(oldName);
contacts.insert(name, address);
} else {
QMessageBox::information(this, tr("Edit Unsuccessful"),
tr("Sorry, \"%1\" is already in your address book.").arg(name));
}
} else if (oldAddress != address) {
QMessageBox::information(this, tr("Edit Successful"),
tr("\"%1\" has been edited in your address book.").arg(name));
contacts[name] = address;
}
}
updateInterface(NavigationMode);
}
void AddressBook::cancel()
{
nameLine->setText(oldName);
addressText->setText(oldAddress);
updateInterface(NavigationMode);
}
void AddressBook::removeContact()
{
QString name = nameLine->text();
QString address = addressText->toPlainText();
if (contacts.contains(name)) {
int button = QMessageBox::question(this,
tr("Confirm Remove"),
tr("Are you sure you want to remove \"%1\"?").arg(name),
QMessageBox::Yes | QMessageBox::No);
if (button == QMessageBox::Yes) {
previous();
contacts.remove(name);
QMessageBox::information(this, tr("Remove Successful"),
tr("\"%1\" has been removed from your address book.").arg(name));
}
}
updateInterface(NavigationMode);
}
void AddressBook::next()
{
QString name = nameLine->text();
QMap<QString, QString>::iterator i = contacts.find(name);
if (i != contacts.end())
i++;
if (i == contacts.end())
i = contacts.begin();
nameLine->setText(i.key());
addressText->setText(i.value());
}
void AddressBook::previous()
{
QString name = nameLine->text();
QMap<QString, QString>::iterator i = contacts.find(name);
if (i == contacts.end()) {
nameLine->clear();
addressText->clear();
return;
}
if (i == contacts.begin())
i = contacts.end();
i--;
nameLine->setText(i.key());
addressText->setText(i.value());
}
void AddressBook::findContact()
{
dialog->show();
if (dialog->exec() == 1) {
QString contactName = dialog->getFindText();
if (contacts.contains(contactName)) {
nameLine->setText(contactName);
addressText->setText(contacts.value(contactName));
} else {
QMessageBox::information(this, tr("Contact Not Found"),
tr("Sorry, \"%1\" is not in your address book.").arg(contactName));
return;
}
}
updateInterface(NavigationMode);
}
void AddressBook::updateInterface(Mode mode)
{
currentMode = mode;
switch (currentMode) {
case AddingMode:
case EditingMode:
nameLine->setReadOnly(false);
nameLine->setFocus(Qt::OtherFocusReason);
addressText->setReadOnly(false);
addButton->setEnabled(false);
editButton->setEnabled(false);
removeButton->setEnabled(false);
nextButton->setEnabled(false);
previousButton->setEnabled(false);
submitButton->show();
cancelButton->show();
loadButton->setEnabled(false);
saveButton->setEnabled(false);
exportButton->setEnabled(false);
break;
case NavigationMode:
if (contacts.isEmpty()) {
nameLine->clear();
addressText->clear();
}
nameLine->setReadOnly(true);
addressText->setReadOnly(true);
addButton->setEnabled(true);
int number = contacts.size();
editButton->setEnabled(number >= 1);
removeButton->setEnabled(number >= 1);
findButton->setEnabled(number > 2);
nextButton->setEnabled(number > 1);
previousButton->setEnabled(number > 1);
submitButton->hide();
cancelButton->hide();
exportButton->setEnabled(number >= 1);
loadButton->setEnabled(true);
saveButton->setEnabled(number >= 1);
break;
}
}
void AddressBook::saveToFile()
{
QString fileName = QFileDialog::getSaveFileName(this,
tr("Save Address Book"), "",
tr("Address Book (*.abk);;All Files (*)"));
if (fileName.isEmpty())
return;
else {
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly)) {
QMessageBox::information(this, tr("Unable to open file"),
file.errorString());
return;
}
QDataStream out(&file);
out.setVersion(QDataStream::Qt_4_3);
out << contacts;
}
updateInterface(NavigationMode);
}
void AddressBook::loadFromFile()
{
QString fileName = QFileDialog::getOpenFileName(this,
tr("Open Address Book"), "",
tr("Address Book (*.abk);;All Files (*)"));
if (fileName.isEmpty())
return;
else {
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly)) {
QMessageBox::information(this, tr("Unable to open file"),
file.errorString());
return;
}
QDataStream in(&file);
in.setVersion(QDataStream::Qt_4_3);
in >> contacts;
QMap<QString, QString>::iterator i = contacts.begin();
nameLine->setText(i.key());
addressText->setText(i.value());
}
updateInterface(NavigationMode);
}
//! [export function part1]
void AddressBook::exportAsVCard()
{
QString name = nameLine->text();
QString address = addressText->toPlainText();
QString firstName;
QString lastName;
QStringList nameList;
int index = name.indexOf(" ");
if (index != -1) {
nameList = name.split(QRegularExpression("\\s+"), Qt::SkipEmptyParts);
firstName = nameList.first();
lastName = nameList.last();
} else {
firstName = name;
lastName = "";
}
QString fileName = QFileDialog::getSaveFileName(this,
tr("Export Contact"), "",
tr("vCard Files (*.vcf);;All Files (*)"));
if (fileName.isEmpty())
return;
QFile file(fileName);
//! [export function part1]
//! [export function part2]
if (!file.open(QIODevice::WriteOnly)) {
QMessageBox::information(this, tr("Unable to open file"),
file.errorString());
return;
}
QTextStream out(&file);
//! [export function part2]
//! [export function part3]
out << "BEGIN:VCARD" << '\n';
out << "VERSION:2.1" << '\n';
out << "N:" << lastName << ';' << firstName << '\n';
if (!nameList.isEmpty())
out << "FN:" << nameList.join(' ') << '\n';
else
out << "FN:" << firstName << '\n';
//! [export function part3]
//! [export function part4]
address.replace(";", "\\;", Qt::CaseInsensitive);
address.replace('\n', ";", Qt::CaseInsensitive);
address.replace(",", " ", Qt::CaseInsensitive);
out << "ADR;HOME:;" << address << '\n';
out << "END:VCARD" << '\n';
QMessageBox::information(this, tr("Export Successful"),
tr("\"%1\" has been exported as a vCard.").arg(name));
}
//! [export function part4]

View File

@ -0,0 +1,68 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef ADDRESSBOOK_H
#define ADDRESSBOOK_H
#include <QWidget>
#include <QMap>
#include "finddialog.h"
QT_BEGIN_NAMESPACE
class QPushButton;
class QLabel;
class QLineEdit;
class QTextEdit;
QT_END_NAMESPACE
class AddressBook : public QWidget
{
Q_OBJECT
public:
AddressBook(QWidget *parent = nullptr);
enum Mode { NavigationMode, AddingMode, EditingMode };
public slots:
void addContact();
void editContact();
void submitContact();
void cancel();
void removeContact();
void findContact();
void next();
void previous();
void saveToFile();
void loadFromFile();
//! [exportAsVCard() declaration]
void exportAsVCard();
//! [exportAsVCard() declaration]
private:
void updateInterface(Mode mode);
QPushButton *addButton;
QPushButton *editButton;
QPushButton *removeButton;
QPushButton *findButton;
QPushButton *submitButton;
QPushButton *cancelButton;
QPushButton *nextButton;
QPushButton *previousButton;
QPushButton *loadButton;
QPushButton *saveButton;
//! [exportButton declaration]
QPushButton *exportButton;
//! [exportButton declaration]
QLineEdit *nameLine;
QTextEdit *addressText;
QMap<QString, QString> contacts;
FindDialog *dialog;
QString oldName;
QString oldAddress;
Mode currentMode;
};
#endif

View File

@ -0,0 +1,47 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QtWidgets>
#include "finddialog.h"
FindDialog::FindDialog(QWidget *parent)
: QDialog(parent)
{
QLabel *findLabel = new QLabel(tr("Enter the name of a contact:"));
lineEdit = new QLineEdit;
findButton = new QPushButton(tr("&Find"));
findText = "";
QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(findLabel);
layout->addWidget(lineEdit);
layout->addWidget(findButton);
setLayout(layout);
setWindowTitle(tr("Find a Contact"));
connect(findButton, &QPushButton::clicked,
this, &FindDialog::findClicked);
connect(findButton, &QPushButton::clicked,
this, &FindDialog::accept);
}
void FindDialog::findClicked()
{
QString text = lineEdit->text();
if (text.isEmpty()) {
QMessageBox::information(this, tr("Empty Field"),
tr("Please enter a name."));
return;
} else {
findText = text;
lineEdit->clear();
hide();
}
}
QString FindDialog::getFindText()
{
return findText;
}

View File

@ -0,0 +1,31 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef FINDDIALOG_H
#define FINDDIALOG_H
#include <QDialog>
QT_BEGIN_NAMESPACE
class QLineEdit;
class QPushButton;
QT_END_NAMESPACE
class FindDialog : public QDialog
{
Q_OBJECT
public:
FindDialog(QWidget *parent = nullptr);
QString getFindText();
public slots:
void findClicked();
private:
QPushButton *findButton;
QLineEdit *lineEdit;
QString findText;
};
#endif

View File

@ -0,0 +1,15 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QtWidgets>
#include "addressbook.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
AddressBook addressBook;
addressBook.show();
return app.exec();
}

View File

@ -0,0 +1,14 @@
QT += widgets
requires(qtConfig(filedialog))
SOURCES = addressbook.cpp \
finddialog.cpp \
main.cpp
HEADERS = addressbook.h \
finddialog.h
QMAKE_PROJECT_NAME = ab_part7
# install
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/tutorials/addressbook/part7
INSTALLS += target