Sur cette page

Table SQL mise en cache

L'exemple de table mise en cache montre comment une vue de table peut être utilisée pour accéder à une base de données, en mettant en cache toutes les modifications apportées aux données jusqu'à ce que l'utilisateur les soumette explicitement à l'aide d'un bouton poussoir.

L'utilisateur met à jour une cellule du tableau et sélectionne le bouton d'envoi pour appliquer la modification dans la base de données.

L'exemple se compose d'une seule classe, TableEditor, qui est un widget de dialogue personnalisé permettant à l'utilisateur de modifier les données stockées dans une base de données. Nous allons d'abord passer en revue la définition de la classe et la manière de l'utiliser, puis nous nous pencherons sur son implémentation.

Définition de la classe TableEditor

La classe TableEditor hérite de QWidget, ce qui fait du widget de l'éditeur de tableau une fenêtre de dialogue de premier niveau.

class TableEditor : public QWidget
{
    Q_OBJECT

public:
    explicit TableEditor(const QString &tableName, QWidget *parent = nullptr);

private slots:
    void submit();

private:
    QPushButton *submitButton;
    QPushButton *revertButton;
    QPushButton *quitButton;
    QDialogButtonBox *buttonBox;
    QSqlTableModel *model;
};

Le constructeur de TableEditor prend deux arguments : Le premier est une référence à la table de la base de données sur laquelle l'objet TableEditor opérera. L'autre est un pointeur sur le widget parent et est transmis au constructeur de la classe de base.

Notez la déclaration de la variable QSqlTableModel: Comme nous le verrons dans cet exemple, la classe QSqlTableModel peut être utilisée pour fournir des données à des classes de vues telles que QTableView. La classe QSqlTableModel fournit un modèle de données modifiable permettant de lire et d'écrire des enregistrements de base de données à partir d'une table unique. Elle est construite au-dessus de la classe de niveau inférieur QSqlQuery qui fournit des moyens d'exécuter et de manipuler des instructions SQL.

Nous allons également montrer comment une vue de table peut être utilisée pour mettre en cache toutes les modifications apportées aux données jusqu'à ce que l'utilisateur demande explicitement de les soumettre. Pour cette raison, nous devons déclarer un slot submit() en plus du modèle et des boutons de l'éditeur.

Connexion à une base de données
Avant de pouvoir utiliser la classe TableEditor, nous devons créer une connexion à la base de données contenant la table que nous voulons modifier :
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    if (!createConnection())
        return 1;

    TableEditor editor("person");
    editor.show();
    return app.exec();
}

La fonction createConnection() est une fonction d'aide fournie pour des raisons de commodité. Elle est définie dans le fichier connection.h qui se trouve dans le répertoire d'exemples sql (tous les exemples du répertoire sql utilisent cette fonction pour se connecter à une base de données).

static bool createConnection()
{
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
    db.setDatabaseName(":memory:");
    if (!db.open()) {
        QMessageBox::critical(nullptr, QObject::tr("Cannot open database"),
            QObject::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.\n\n"
                        "Click Cancel to exit."), QMessageBox::Cancel);
        return false;
    }

    QSqlQuery query;
    query.exec("create table person (id int primary key, "
               "firstname varchar(20), lastname varchar(20))");
    query.exec("insert into person values(101, 'Danny', 'Young')");
    query.exec("insert into person values(102, 'Christine', 'Holand')");
    query.exec("insert into person values(103, 'Lars', 'Gordon')");
    query.exec("insert into person values(104, 'Roberto', 'Robitaille')");
    query.exec("insert into person values(105, 'Maria', 'Papadopoulos')");

    query.exec("create table items (id int primary key,"
                                             "imagefile int,"
                                             "itemtype varchar(20),"
                                             "description varchar(100))");
    query.exec("insert into items "
               "values(0, 0, 'Qt',"
               "'Qt is a full development framework with tools designed to "
               "streamline the creation of stunning applications and  "
               "amazing user interfaces for desktop, embedded and mobile "
               "platforms.')");
    query.exec("insert into items "
               "values(1, 1, 'Qt Quick',"
               "'Qt Quick is a collection of techniques designed to help "
               "developers create intuitive, modern-looking, and fluid "
               "user interfaces using a CSS & JavaScript like language.')");
    query.exec("insert into items "
               "values(2, 2, 'Qt Creator',"
               "'Qt Creator is a powerful cross-platform integrated "
               "development environment (IDE), including UI design tools "
               "and on-device debugging.')");
    query.exec("insert into items "
               "values(3, 3, 'Qt Project',"
               "'The Qt Project governs the open source development of Qt, "
               "allowing anyone wanting to contribute to join the effort "
               "through a meritocratic structure of approvers and "
               "maintainers.')");

    query.exec("create table images (itemid int, file varchar(20))");
    query.exec("insert into images values(0, 'images/qt-logo.png')");
    query.exec("insert into images values(1, 'images/qt-quick.png')");
    query.exec("insert into images values(2, 'images/qt-creator.png')");
    query.exec("insert into images values(3, 'images/qt-project.png')");

    return true;
}

La fonction createConnection ouvre une connexion à une base de données SQLITE en mémoire et crée une table de test. Si vous souhaitez utiliser une autre base de données, il vous suffit de modifier le code de cette fonction.

Implémentation de la classe TableEditor

L'implémentation de la classe ne comporte que deux fonctions, le constructeur et le slot submit(). Dans le constructeur, nous créons et personnalisons le modèle de données et les différents éléments de la fenêtre :

TableEditor::TableEditor(const QString &tableName, QWidget *parent)
    : QWidget(parent)
{
    model = new QSqlTableModel(this);
    model->setTable(tableName);
    model->setEditStrategy(QSqlTableModel::OnManualSubmit);
    model->select();

    model->setHeaderData(0, Qt::Horizontal, tr("ID"));
    model->setHeaderData(1, Qt::Horizontal, tr("First name"));
    model->setHeaderData(2, Qt::Horizontal, tr("Last name"));

Tout d'abord, nous créons le modèle de données et définissons la table de la base de données SQL sur laquelle le modèle doit fonctionner. Notez que la fonction QSqlTableModel::setTable() ne sélectionne pas les données de la table ; elle récupère uniquement les informations sur les champs. C'est pourquoi nous appelons la fonction QSqlTableModel::select() ultérieurement, afin de remplir le modèle avec les données de la table. La sélection peut être personnalisée en spécifiant des filtres et des conditions de tri (voir la documentation de la classe QSqlTableModel pour plus de détails).

Nous définissons également la stratégie d'édition du modèle. La stratégie d'édition dicte le moment où les modifications effectuées par l'utilisateur dans la vue sont réellement appliquées à la base de données. Puisque nous voulons mettre en cache les modifications dans la vue de la table (c'est-à-dire dans le modèle) jusqu'à ce que l'utilisateur les soumette explicitement, nous choisissons la stratégie QSqlTableModel::OnManualSubmit. Les alternatives sont QSqlTableModel::OnFieldChange et QSqlTableModel::OnRowChange.

Enfin, nous configurons les étiquettes affichées dans l'en-tête de la vue à l'aide de la fonction setHeaderData() que le modèle hérite de la classe QSqlQueryModel.

    QTableView *view = new QTableView;
    view->setModel(model);
    view->resizeColumnsToContents();

Nous créons ensuite une vue de table. La classe QTableView fournit une implémentation modèle/vue par défaut d'une vue de tableau, c'est-à-dire qu'elle implémente une vue de tableau qui affiche des éléments d'un modèle. Elle permet également à l'utilisateur de modifier les éléments, en stockant les modifications dans le modèle. Pour créer une vue en lecture seule, définissez l'indicateur approprié à l'aide de la propriété editTriggers. La vue hérite de la classe QAbstractItemView.

Pour que la vue présente nos données, nous lui transmettons notre modèle à l'aide de la fonction setModel().

    submitButton = new QPushButton(tr("Submit"));
    submitButton->setDefault(true);
    revertButton = new QPushButton(tr("&Revert"));
    quitButton = new QPushButton(tr("Quit"));

    buttonBox = new QDialogButtonBox(Qt::Vertical);
    buttonBox->addButton(submitButton, QDialogButtonBox::ActionRole);
    buttonBox->addButton(revertButton, QDialogButtonBox::ActionRole);
    buttonBox->addButton(quitButton, QDialogButtonBox::RejectRole);

Les boutons de TableEditor sont des objets QPushButton ordinaires. Nous les ajoutons à une boîte à boutons pour nous assurer que les boutons sont présentés dans une disposition appropriée au style du widget actuel. La raison en est que les boîtes de dialogue et de message présentent généralement les boutons dans une disposition conforme aux directives d'interface de la plate-forme concernée. Invariablement, les différentes plateformes ont des dispositions différentes pour leurs boîtes de dialogue. QDialogButtonBox permet à un développeur d'ajouter des boutons et utilisera automatiquement la disposition appropriée pour l'environnement de bureau de l'utilisateur.

La plupart des boutons d'une boîte de dialogue suivent certains rôles. Lorsque vous ajoutez un bouton à une boîte à boutons à l'aide de la fonction addButton(), le rôle du bouton doit être spécifié à l'aide de l'énumération QDialogButtonBox::ButtonRole. Par ailleurs, QDialogButtonBox fournit plusieurs boutons standard (par exemple OK, Cancel, Save) que vous pouvez utiliser. Ils existent en tant que drapeaux afin que vous puissiez les associer dans le constructeur.

    connect(submitButton, &QPushButton::clicked, this, &TableEditor::submit);
    connect(revertButton, &QPushButton::clicked,  model, &QSqlTableModel::revertAll);
    connect(quitButton, &QPushButton::clicked, this, &TableEditor::close);

Nous connectons le bouton Quit à l'emplacement close() de l'éditeur de tableau, et le bouton Submit à notre emplacement privé submit(). Ce dernier emplacement se chargera des transactions de données. Enfin, nous connectons le bouton Revert à l'emplacement revertAll() de notre modèle, afin d'annuler toutes les modifications en cours (c'est-à-dire de restaurer les données d'origine).

    QHBoxLayout *mainLayout = new QHBoxLayout;
    mainLayout->addWidget(view);
    mainLayout->addWidget(buttonBox);
    setLayout(mainLayout);

    setWindowTitle(tr("Cached Table"));
}

Enfin, nous ajoutons la boîte à boutons et la vue du tableau à une disposition, nous installons la disposition sur le widget de l'éditeur de tableau et nous définissons le titre de la fenêtre de l'éditeur.

void TableEditor::submit()
{
    model->database().transaction();
    if (model->submitAll()) {
        model->database().commit();
    } else {
        model->database().rollback();
        QMessageBox::warning(this, tr("Cached Table"),
                             tr("The database reported an error: %1")
                             .arg(model->lastError().text()));
    }
}

Le slot submit() est appelé chaque fois que les utilisateurs appuient sur le bouton Submit pour enregistrer leurs modifications.

Tout d'abord, nous commençons une transaction sur la base de données à l'aide de la fonction QSqlDatabase::transaction(). Une transaction de base de données est une unité d'interaction avec un système de gestion de base de données ou un système similaire qui est traitée de manière cohérente et fiable, indépendamment des autres transactions. Un pointeur vers la base de données utilisée peut être obtenu à l'aide de la fonction QSqlTableModel::database().

Ensuite, nous essayons de soumettre tous les changements en attente, c'est-à-dire les éléments modifiés du modèle. Si aucune erreur ne se produit, nous validons la transaction dans la base de données à l'aide de la fonction QSqlDatabase::commit() (notez que sur certaines bases de données, cette fonction ne fonctionnera pas s'il y a un QSqlQuery actif sur la base de données). Dans le cas contraire, nous effectuons un retour en arrière de la transaction à l'aide de la fonction QSqlDatabase::rollback() et affichons un avertissement à l'intention de l'utilisateur.

Voir aussi :

Une liste complète des classes de base de données SQL de Qt, et la documentation sur la programmation modèle/vue.

Exemple de projet @ 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.