Qt Reference Documentation

# Carnet d'adresse 5 - Ajout d'une fonction de recherche

Files:

- tutorials/addressbook-fr/part5/addressbook.cpp
- tutorials/addressbook-fr/part5/addressbook.h
- tutorials/addressbook-fr/part5/finddialog.cpp
- tutorials/addressbook-fr/part5/finddialog.h
- tutorials/addressbook-fr/part5/main.cpp
- tutorials/addressbook-fr/part5/part5.pro

Dans ce chapitre, nous allons voir les possibilités pour rechercher des contacts dans le carnet d'adresse.

Plus nous ajoutons des contacts dans l'application, plus il devient difficile de naviguer avec les boutons Next et Previous. Dans ce cas, une fonction de recherche serait plus efficace pour rechercher les contacts. La capture d'écran ci-dessus montre le bouton de recherche Find et sa position dans le paneau de bouton.

Lorsque l'utilisateur clique sur le bouton Find, il est courant d'afficher une boîte de dialogue qui demande à l'utilisateur d'entrer un nom de contact. Qt fournit la classe QDialog, que nous sous-classons dans ce chapitre pour implémenter la class `FindDialog`.

## Définition de la classe FindDialog

Pour sous-classer QDialog, nous commençons par inclure le header de QDialog dans le fichier `finddialog.h`. De plus, nous déclarons les classes QLineEdit et QPushButton car nous utilisons ces widgets dans notre classe dialogue.

Tout comme dans la classe `AddressBook`, la classe `FindDialog` utilise la macro Q_OBJECT et son constructeur est défini de façon à accepter un QWidget parent, même si cette boîte de dialogue sera affichée dans une fenêtre séparée.

     #include <QDialog>

     class QLineEdit;
     class QPushButton;

     class FindDialog : public QDialog
     {
         Q_OBJECT

     public:
         FindDialog(QWidget *parent = 0);
         QString getFindText();

     public slots:
         void findClicked();

     private:
         QPushButton *findButton;
         QLineEdit *lineEdit;
         QString findText;
     };

Nous définissons la méthode publique `getFindText()` pour être utilisée par les classes qui instancient `FindDialog`, ce qui leur permet d'obtenir le texte entré par l'utilisateur. Un slot public, `findClicked()`, est défini pour prendre en charge le texte lorsque l'utilisateur clique sur le bouton Find.

Finalement, nous définissons les variables privées `findButton`, `lineEdit` et `findText`, qui correspondent respectivement au bouton Find, au champ de texte dans lequel l'utilisateur tape le texte à rechercher, et à une variable interne stockant le texte pour une utilisation ultérieure.

## Implémentation de la classe FindDialog

Dans le constructeur de `FindDialog`, nous instancions les objets des variables privées `lineEdit`, `findButton` et `findText`. Nous utilisons ensuite un QHBoxLayout pour positionner les 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, SIGNAL(clicked()), this, SLOT(findClicked()));
         connect(findButton, SIGNAL(clicked()), this, SLOT(accept()));
     }

Nous mettons en place la mise en page et le titre de la fenêtre, et nous connectons les signaux aux slots. Remarquez que le signal clicked() de `findButton` est connecté à `findClicked()` et accept(). Le slot accept() fourni par le QDialog ferme la boîte de dialogue et lui donne le code de retour Accepted. Nous utilisons cette fonction pour aider la méthode `findContact()` de la classe `AddressBook` à savoir si l'objet `FindDialog` a été fermé. Ceci sera expliqué plus loin lorsque nous verrons la méthode `findContact()`.

Dans `findClicked()`, nous validons le champ de texte pour nous assurer que l'utilisateur n'a pas cliqué sur le bouton Find sans avoir entré un nom de contact. Ensuite, nous stockons le texte du champ d'entrée `lineEdit` dans `findText`. Et finalement nous vidons le contenu de `lineEdit` et cachons la boîte de dialogue.

     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();
         }
     }

La variable `findText` a un accesseur publique associé: `getFindText()`. Étant donné que nous ne modifions `findText` directement que dans le constructeur et la méthode `findClicked()`, nous ne créons pas de manipulateurs associé à `getFindText()`. Puisque `getFindText()` est publique, les classes instanciant et utilisant `FindDialog` peuvent toujours accéder à la chaîne de caractères que l'utilisateur a entré et accepté.

     QString FindDialog::getFindText()
     {
         return findText;
     }

## Définition de la classe AddressBook

Pour utiliser `FindDialog` depuis la classe `AddressBook`, nous incluons `finddialog.h` dans le fichier `addressbook.h`.

     #include "finddialog.h"

Jusqu'ici, toutes les fonctionnalités du carnet d'adresses ont un QPushButton et un slot correspondant. De la même façon, pour la fonctionnalité Find, nous avons `findButton` et `findContact()`.

Le `findButton` est déclaré comme une variable privée et la méthode `findContact()` est déclarée comme un slot public.

         void findContact();
         ...
         QPushButton *findButton;

Finalement, nous déclarons la variable privée `dialog` que nous allons utiliser pour accéder à une instance de `FindDialog`.

         FindDialog *dialog;

Une fois que nous avons instancié la boîte de dialogue, nous voulons l'utiliser plus qu'une fois. Utiliser une variable privée nous permet d'y référer à plus d'un endroit dans la classe.

## Implémentation de la classe AddressBook

Dans le constructeur de `AddressBook`, nous instancions nos objets privés, `findbutton` et `findDialog`:

         findButton = new QPushButton(tr("&Find"));
         findButton->setEnabled(false);
         ...
         dialog = new FindDialog;

Ensuite, nous connectons le signal clicked() de `findButton` à `findContact()`.

         connect(findButton, SIGNAL(clicked()), this, SLOT(findContact()));

Maintenant, tout ce qui manque est le code de notre méthode `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);
     }

Nous commençons par afficher l'instance de `FindDialog`, `dialog`. L'utilisateur peut alors entrer le nom du contact à rechercher. Lorsque l'utilisateur clique sur le bouton `findButton`, la boîte de dialogue est masquée et le code de retour devient QDialog::Accepted. Ce code de retour vient remplir la condition du premier if.

Ensuite, nous extrayons le texte que nous utiliserons pour la recherche, il s'agit ici de `contactName` obtenu à l'aide de la méthode `getFindText()` de `FindDialog`. Si le contact existe dans le carnet d'adresse, nous l'affichons directement. Sinon, nous affichons le QMessageBox suivant pour indiquer que la recherche à échouée.