Sur cette page

Exemple d'utilisation de SQL Widget Mapper

L'exemple SQL Widget Mapper montre comment utiliser un mappage d'informations provenant d'une base de données vers des widgets d'un formulaire.

La fenêtre principale affiche le nom de l'utilisateur, son adresse et indique le type d'adresse.

Dans l’exemple « Combo Widget Mapper », nous avons montré comment utiliser un mappage nommé entre un mappage de widget et un widget « QComboBox » doté d’un modèle à usage spécifique, afin de relier les valeurs du modèle à une liste de choix.

Ici encore, nous créons une classe « Window » dotée d’une interface utilisateur presque identique, proposant une liste déroulante permettant de classer les adresses en « Domicile », « Travail » ou « Autre ». Cependant, au lieu d’utiliser un modèle distinct pour stocker ces types d’adresses, nous utilisons une table de base de données pour stocker les données d’exemple et une autre pour stocker les types d’adresses. De cette manière, nous stockons toutes les informations au même endroit.

Définition de la classe Window

La classe fournit un constructeur, un slot permettant de maintenir les boutons à jour, ainsi qu’une fonction privée pour configurer le modèle :

class Window : public QWidget
{
    Q_OBJECT

public:
    Window(QWidget *parent = nullptr);

private slots:
    void updateButtons(int row);

private:
    void setupModel();

    QLabel *nameLabel;
    QLabel *addressLabel;
    QLabel *typeLabel;
    QLineEdit *nameEdit;
    QTextEdit *addressEdit;
    QComboBox *typeComboBox;
    QPushButton *nextButton;
    QPushButton *previousButton;

    QSqlRelationalTableModel *model;
    QItemSelectionModel *selectionModel;
    QDataWidgetMapper *mapper;
    int typeIndex;
};

Outre l’objet ` QDataWidgetMapper ` et les contrôles utilisés pour constituer l’interface utilisateur, nous utilisons un `QStandardItemModel` pour stocker nos données et un ` QStringListModel ` pour stocker les informations relatives aux types d’adresse pouvant être appliqués aux données de chaque personne.

Implémentation de la classe Window

La première action effectuée par le constructeur de la classe ` Window ` consiste à configurer le modèle utilisé pour stocker les données de l’exemple. Comme il s’agit d’un élément clé de l’exemple, nous allons l’examiner en premier lieu.

Le modèle est initialisé dans la fonction ` setupModel() ` de la fenêtre. Nous y créons une base de données SQLite contenant une table « person » avec les champs « primary key », « name », « address » et « type ».

void Window::setupModel()
{
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
    db.setDatabaseName(":memory:");
    if (!db.open()) {
        QMessageBox::critical(0, tr("Cannot open database"),
            tr("Unable to establish a database connection.\n"
               "This example needs SQLite support. Please read "
               "the Qt SQL driver documentation for information how "
               "to build it."), QMessageBox::Cancel);
        return;
    }

    QSqlQuery query;
    query.exec("create table person (id int primary key, "
               "name varchar(20), address varchar(200), typeid int)");
    query.exec("insert into person values(1, 'Alice', "
               "'<qt>123 Main Street<br/>Market Town</qt>', 101)");
    query.exec("insert into person values(2, 'Bob', "
               "'<qt>PO Box 32<br/>Mail Handling Service"
               "<br/>Service City</qt>', 102)");
    query.exec("insert into person values(3, 'Carol', "
               "'<qt>The Lighthouse<br/>Remote Island</qt>', 103)");
    query.exec("insert into person values(4, 'Donald', "
               "'<qt>47338 Park Avenue<br/>Big City</qt>', 101)");
    query.exec("insert into person values(5, 'Emma', "
               "'<qt>Research Station<br/>Base Camp<br/>"
               "Big Mountain</qt>', 103)");

Dans chaque ligne de la table, nous insérons des valeurs par défaut pour ces champs, y compris les valeurs correspondant aux types d’adresse, qui sont stockées dans une table distincte.

La fenêtre principale affiche un tableau contenant les informations stockées dans la base de données.

Nous créons une table « addresstype » contenant les identifiants utilisés dans la table « person » et les chaînes de caractères correspondantes :

    query.exec("create table addresstype (id int, description varchar(20))");
    query.exec("insert into addresstype values(101, 'Home')");
    query.exec("insert into addresstype values(102, 'Work')");
    query.exec("insert into addresstype values(103, 'Other')");

    model = new QSqlRelationalTableModel(this);
    model->setTable("person");
    model->setEditStrategy(QSqlTableModel::OnManualSubmit);

    typeIndex = model->fieldIndex("typeid");

    model->setRelation(typeIndex,
           QSqlRelation("addresstype", "id", "description"));
    model->select();
}

Le champ « typeid » de la table « person » est lié au contenu de la table « addresstype » via une relation définie dans une QSqlRelationalTableModel. Ce type de modèle effectue tout le travail nécessaire au stockage des données dans une base de données et permet également d’utiliser n’importe quelle relation comme modèle à part entière.

Dans ce cas précis, nous avons défini une relation pour le champ « typeid » de la table « person » qui le relie au champ « id » de la table « addresstype » et qui fait en sorte que le contenu du champ « description » soit utilisé partout où le « typeid » est présenté à l’utilisateur. (Voir la documentation relative à la méthode ` QSqlRelationalTableModel::setRelation()` pour plus de détails.)

Le tableau présente la relation entre le champ « typeid » et le « addresstype ».

Le constructeur de la classe ` Window ` peut être expliqué en trois parties. Dans la première partie, nous configurons le modèle utilisé pour stocker les données, puis nous configurons les widgets utilisés pour l’interface utilisateur :

Window::Window(QWidget *parent)
    : QWidget(parent)
{
    setupModel();

    nameLabel = new QLabel(tr("Na&me:"));
    nameEdit = new QLineEdit();
    addressLabel = new QLabel(tr("&Address:"));
    addressEdit = new QTextEdit();
    typeLabel = new QLabel(tr("&Type:"));
    typeComboBox = new QComboBox();
    nextButton = new QPushButton(tr("&Next"));
    previousButton = new QPushButton(tr("&Previous"));

    nameLabel->setBuddy(nameEdit);
    addressLabel->setBuddy(addressEdit);
    typeLabel->setBuddy(typeComboBox);

Nous obtenons un modèle pour la liste déroulante à partir du modèle principal, sur la base de la relation que nous avons définie pour le champ « typeid ». L’appel à la méthode setModelColumn() de la liste déroulante sélectionne le champ du modèle à afficher.

Notez que cette approche est similaire à celle utilisée dans l’exemple « Combo Widget Mapper » dans la mesure où nous configurons un modèle pour la liste déroulante. Cependant, dans ce cas, nous obtenons un modèle basé sur une relation de l’ QSqlRelationalTableModel plutôt que d’en créer un séparé.

Ensuite, nous configurons le mappeur de widgets, en associant chaque widget d’entrée à un champ du modèle :

    QSqlTableModel *relModel = model->relationModel(typeIndex);
    typeComboBox->setModel(relModel);
    typeComboBox->setModelColumn(relModel->fieldIndex("description"));

    mapper = new QDataWidgetMapper(this);
    mapper->setModel(model);
    mapper->setItemDelegate(new QSqlRelationalDelegate(this));
    mapper->addMapping(nameEdit, model->fieldIndex("name"));
    mapper->addMapping(addressEdit, model->fieldIndex("address"));
    mapper->addMapping(typeComboBox, typeIndex);

Pour la liste déroulante, nous connaissons déjà l’index du champ dans le modèle grâce à la fonction ` setupModel() `. Nous utilisons un ` QSqlRelationalDelegate ` comme intermédiaire entre le mappeur et les widgets de saisie afin de faire correspondre les valeurs « typeid » du modèle avec celles du modèle de la liste déroulante, et de remplir la liste déroulante avec des descriptions plutôt qu’avec des valeurs entières.

Ainsi, l'utilisateur peut sélectionner un élément dans la liste déroulante, et la valeur associée est réécrite dans le modèle.

Le reste du constructeur configure les connexions et les mises en page :

    connect(previousButton, &QPushButton::clicked,
            mapper, &QDataWidgetMapper::toPrevious);
    connect(nextButton, &QPushButton::clicked,
            mapper, &QDataWidgetMapper::toNext);
    connect(mapper, &QDataWidgetMapper::currentIndexChanged,
            this, &Window::updateButtons);

    QGridLayout *layout = new QGridLayout();
    layout->addWidget(nameLabel, 0, 0, 1, 1);
    layout->addWidget(nameEdit, 0, 1, 1, 1);
    layout->addWidget(previousButton, 0, 2, 1, 1);
    layout->addWidget(addressLabel, 1, 0, 1, 1);
    layout->addWidget(addressEdit, 1, 1, 2, 1);
    layout->addWidget(nextButton, 1, 2, 1, 1);
    layout->addWidget(typeLabel, 3, 0, 1, 1);
    layout->addWidget(typeComboBox, 3, 1, 1, 1);
    setLayout(layout);

    setWindowTitle(tr("SQL Widget Mapper"));
    mapper->toFirst();
}

Par souci d'exhaustivité, nous présentons ici l'implémentation du slot « updateButtons() » :

void Window::updateButtons(int row)
{
    previousButton->setEnabled(row > 0);
    nextButton->setEnabled(row < model->rowCount() - 1);
}

Résumé et lectures complémentaires

L’utilisation d’un modèle distinct pour la liste déroulante et d’un délégué spécial pour le mappeur de widget nous permet de présenter un menu de choix à l’utilisateur. Bien que ces choix soient stockés dans la même base de données que les données de l’utilisateur, ils sont conservés dans une table distincte. Grâce à cette approche, nous pouvons reconstituer des enregistrements complets ultérieurement tout en utilisant correctement les fonctionnalités de la base de données.

Même si les modèles SQL ne sont pas utilisés, il est toujours possible d’utiliser plusieurs modèles pour présenter des choix à l’utilisateur. Ce sujet est abordé dans l’exemple « Combo Widget Mapper ».

Exemple de projet sur code.qt.io

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.