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

Dans l'exemple Combo Widget Mapper, nous avons montré comment utiliser un mappage nommé entre un mappeur de widgets et un widget QComboBox avec un modèle spécial pour relier les valeurs du modèle à une liste de choix.
Nous créons à nouveau une classe Window avec une interface utilisateur presque identique, fournissant une boîte combinée permettant de classer les adresses comme "Domicile", "Travail" ou "Autre". Cependant, au lieu d'utiliser un modèle distinct pour contenir ces types d'adresses, nous utilisons une table de base de données pour contenir les données de l'exemple et une autre pour contenir les types d'adresses. De cette manière, nous stockons toutes les informations au même endroit.
Définition de la classe de fenêtre
La classe fournit un constructeur, un slot pour maintenir les boutons à jour et 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 modèle QStandardItemModel pour contenir nos données et un modèle QStringListModel pour contenir des informations sur les types d'adresse qui peuvent être appliqués aux données de chaque personne.
Mise en œuvre de la classe de fenêtre
La première action effectuée par le constructeur de la classe Window est de mettre en place le modèle utilisé pour contenir les données de l'exemple. Étant donné qu'il s'agit d'une partie essentielle de l'exemple, nous l'examinerons 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 "personne" avec des champs de clé primaire, de nom, d'adresse et de 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)");
Sur chaque ligne de la table, nous insérons des valeurs par défaut pour ces champs, y compris des valeurs pour les types d'adresse qui correspondent aux types d'adresse stockés dans une table séparée.

Nous créons une table "addresstype" contenant les identifiants utilisés dans la table "person" et les chaînes 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 "personne" est lié au contenu de la table "addresstype" par une relation dans un modèle QSqlRelationalTableModel. Ce type de modèle effectue tout le travail nécessaire pour stocker les données dans une base de données et permet également d'utiliser toutes les relations comme des modèles à part entière.
Dans le cas présent, 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 que le contenu du champ "description" est utilisé chaque fois que le "typeid" est présenté à l'utilisateur. (Voir la documentation de QSqlRelationalTableModel::setRelation() pour plus de détails).

Le constructeur de la classe Window peut être expliqué en trois parties. Dans la première partie, nous définissons le modèle utilisé pour contenir les données, puis nous définissons 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 établie pour le champ "typeid". L'appel à la fonction setModelColumn() de la boîte combinée sélectionne le champ dans le champ du modèle à afficher.
Notez que cette approche est similaire à celle utilisée dans l'exemple de mappage du widget Combo, dans la mesure où nous avons défini un modèle pour la liste déroulante. Cependant, dans ce cas, nous obtenons un modèle basé sur une relation dans le site QSqlRelationalTableModel plutôt que d'en créer un autre.
Ensuite, nous configurons le mappeur de widgets, en reliant chaque widget de saisie à 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 proxy entre le mappeur et les widgets de saisie pour faire correspondre les valeurs "typeid" du modèle avec celles du modèle de la boîte combinée et pour remplir la boîte combinée avec des descriptions plutôt qu'avec des valeurs entières.
En conséquence, l'utilisateur peut sélectionner un élément dans la liste déroulante et la valeur associée est écrite dans le modèle.
Le reste du constructeur établit 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(); }
Nous montrons l'implémentation du slot updateButtons() par souci d'exhaustivité :
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 widgets nous permet de présenter un menu de choix à l'utilisateur. Bien que les 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 reconstruire ultérieurement des enregistrements complets tout en utilisant les fonctionnalités de la base de données de manière appropriée.
Si les modèles SQL ne sont pas utilisés, il est toujours possible d'utiliser plus d'un modèle pour présenter les choix à l'utilisateur. C'est ce que couvre l'exemple Combo Widget Mapper.
© 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.