Part 5 - Adding a Find Function#
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 Next and Previous 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
Defining the FindDialog Class#
In order to subclass
QDialog , we first include the header for
QDialog in the
finddialog.h file. Also, we use forward declaration to declare
QPushButton since we will be using those widgets in our dialog class.
As in our
AddressBook class, the
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.
from PySide6.QtWidgets import QDialog QT_BEGIN_NAMESPACE class QLineEdit(): class QPushButton(): QT_END_NAMESPACE class FindDialog(QDialog): Q_OBJECT # public FindDialog(QWidget parent = None) getFindText = QString() slots: = public() def findClicked(): # private findButton = QPushButton() lineEdit = QLineEdit() findText = QString()
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,
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.
Implementing the FindDialog Class#
Within the constructor of
FindDialog, we set up the private variables,
findText. We use a
QHBoxLayout to position the widgets.
def __init__(self, parent): QDialog.__init__(self, parent) findLabel = QLabel(tr("Enter the name of a contact:")) lineEdit = QLineEdit findButton = QPushButton(tr("Find")) findText = "" layout = QHBoxLayout() layout.addWidget(findLabel) layout.addWidget(lineEdit) layout.addWidget(findButton) setLayout(layout) setWindowTitle(tr("Find a Contact")) connect(findButton, QPushButton.clicked, self, FindDialog.findClicked) connect(findButton, QPushButton.clicked, self, FindDialog.accept)
We set the layout and window title, as well as connect the signals to their respective slots. Notice that
clicked() signal is connected to
accept() . The
accept() slot provided by
QDialog hides the dialog and sets the result code to
Accepted . We use this function to help
findContact() function know when the
FindDialog object has been closed. We will explain this logic in further detail when discussing the
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.
<Code snippet "tutorials/addressbook/part5/finddialog.cpp:findClicked() function" not found>
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() is public, classes instantiating and using
FindDialog can always access the search string that the user has entered and accepted.
<Code snippet "tutorials/addressbook/part5/finddialog.cpp:getFindText() function" not found>
Defining the AddressBook Class#
To ensure we can use
FindDialog from within our
AddressBook class, we include
finddialog.h in the
from finddialog import *
So far, all our address book features have a
QPushButton and a corresponding slot. Similarly, for the Find feature we have
findButton is declared as a private variable and the
findContact() function is declared as a public slot.
<Code snippet "tutorials/addressbook/part5/addressbook.h:findContact() declaration" not found> ... findButton = QPushButton()
Lastly, we declare the private variable,
dialog, which we will use to refer to an instance of
dialog = FindDialog()
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.
Implementing the AddressBook Class#
AddressBook class’s constructor, we instantiate our private objects,
findButton = QPushButton(tr("Find")) findButton.setEnabled(False) ... dialog = FindDialog(self)
Next, we connect the
clicked() signal to
connect(findButton, QPushButton.clicked, self, AddressBook.findContact)
Now all that is left is the code for our
<Code snippet "tutorials/addressbook/part5/addressbook.cpp:findContact() function" not found>
We start out by displaying the
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
Accepted . This ensures that our
if statement is always true.
We then proceed to extract the search string, which in this case is
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.