Describes how to add a find function.
Here we look at ways to locate contacts and addresses in the address book.
As we add contacts to our address book, it becomes tedious to navigate the list with the 下一 and 上一 buttons. A Find function would be more efficient. The screenshot above shows the Find button and its position on the panel of buttons.
When the user clicks on the
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
FindDialog
类。
In order to subclass
QDialog
, we first include the header for
QDialog
在
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
AddressBook
class, the
FindDialog
类包括
Q_OBJECT
macro and its constructor is defined to accept a parent
QWidget
, even though the dialog will be opened as a separate window.
#include <QDialog> class QLineEdit; class QPushButton; class FindDialog : public QDialog { Q_OBJECT public: FindDialog(QWidget *parent = nullptr); QString getFindText(); public slots: void findClicked(); private: QPushButton *findButton; QLineEdit *lineEdit; QString findText; };
We define a public function,
getFindText()
, to be used by classes that instantiate
FindDialog
. This function allows these classes to obtain the search string entered by the user. A public slot,
findClicked()
, is also defined to handle the search string when the user clicks the
Find
button.
Lastly, we define the private variables,
findButton
,
lineEdit
and
findText
, corresponding to the
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.
Within the constructor of
FindDialog
, we set up the private variables,
lineEdit
,
findButton
and
findText
. We use a
QHBoxLayout
to position the widgets.
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); }
We set the layout and window title, as well as connect the signals to their respective slots. Notice that
findButton
's
clicked()
signal is connected to
findClicked()
and
accept()
。
accept()
slot provided by
QDialog
hides the dialog and sets the result code to
接受
. We use this function to help
AddressBook
's
findContact()
function know when the
FindDialog
object has been closed. We will explain this logic in further detail when discussing the
findContact()
函数。
在
findClicked()
, we validate
lineEdit
to ensure that the user did not click the
Find
button without entering a contact's name. Then, we set
findText
to the search string, extracted from
lineEdit
. After that, we clear the contents of
lineEdit
and hide the dialog.
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(); } }
The
findText
variable has a public getter function,
getFindText()
, associated with it. Since we only ever set
findText
directly in both the constructor and in the
findClicked()
function, we do not create a setter function to accompany
getFindText()
. Because
getFindText()
is public, classes instantiating and using
FindDialog
can always access the search string that the user has entered and accepted.
QString FindDialog::getFindText() { return findText; }
To ensure we can use
FindDialog
from within our
AddressBook
class, we include
finddialog.h
在
addressbook.h
文件。
#include "finddialog.h"
So far, all our address book features have a
QPushButton
and a corresponding slot. Similarly, for the
Find
feature we have
findButton
and
findContact()
.
The
findButton
is declared as a private variable and the
findContact()
function is declared as a public slot.
void findContact(); ... QPushButton *findButton;
Lastly, we declare the private variable,
dialog
, which we will use to refer to an instance of
FindDialog
.
FindDialog *dialog;
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.
在
AddressBook
class's constructor, we instantiate our private objects,
findButton
and
findDialog
:
findButton = new QPushButton(tr("&Find")); findButton->setEnabled(false); ... dialog = new FindDialog(this);
Next, we connect the
findButton
's
clicked()
signal to
findContact()
.
connect(findButton, &QPushButton::clicked, this, &AddressBook::findContact);
Now all that is left is the code for our
findContact()
函数:
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); }
We start out by displaying the
FindDialog
instance,
dialog
. This is when the user enters a contact name to look up. Once the user clicks the dialog's
findButton
, the dialog is hidden and the result code is set to
QDialog::Accepted
. This ensures that our
if
statement is always true.
We then proceed to extract the search string, which in this case is
contactName
,使用
FindDialog
's
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.