Auf dieser Seite

Zwischengespeicherte SQL-Tabelle

Das Beispiel „Cached Table“ zeigt, wie eine Tabellenansicht für den Zugriff auf eine Datenbank verwendet werden kann, wobei alle Änderungen an den Daten zwischengespeichert werden, bis der Benutzer sie explizit über eine Schaltfläche übermittelt.

Der Benutzer aktualisiert eine Zelle in der Tabelle und klickt auf die Schaltfläche „Absenden“, um die Änderung in der Datenbank zu übernehmen.

Das Beispiel besteht aus einer einzigen Klasse, „ TableEditor “, bei der es sich um ein benutzerdefiniertes Dialog-Widget handelt, mit dem der Benutzer in einer Datenbank gespeicherte Daten ändern kann. Wir werden zunächst die Klassendefinition und die Verwendung der Klasse betrachten und anschließend einen Blick auf die Implementierung werfen.

Klassendefinition von „TableEditor“

Die Klasse „ TableEditor “ erbt von „ QWidget “, wodurch das Tabelleneditor-Widget zu einem Dialogfenster der obersten Ebene wird.

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

Der Konstruktor von „ TableEditor “ nimmt zwei Argumente entgegen: Das erste ist eine Referenz auf die Datenbanktabelle, auf die das „ TableEditor “-Objekt zugreift. Das andere ist ein Zeiger auf das übergeordnete Widget, der an den Konstruktor der Basisklasse weitergereicht wird.

Beachten Sie die Variablendeklaration von ` QSqlTableModel `: Wie wir in diesem Beispiel sehen werden, kann die Klasse ` QSqlTableModel ` verwendet werden, um Daten für Ansichtsklassen wie ` QTableView` bereitzustellen. Die Klasse ` QSqlTableModel ` stellt ein bearbeitbares Datenmodell bereit, das das Lesen und Schreiben von Datenbankdatensätzen aus einer einzelnen Tabelle ermöglicht. Sie baut auf der untergeordneten Klasse ` QSqlQuery ` auf, die Mittel zur Ausführung und Bearbeitung von SQL-Anweisungen bereitstellt.

Außerdem werden wir zeigen, wie eine Tabellenansicht genutzt werden kann, um Änderungen an den Daten zwischenzuspeichern, bis der Benutzer ausdrücklich die Übermittlung anfordert. Aus diesem Grund müssen wir zusätzlich zum Modell und den Schaltflächen des Editors einen „ submit() “-Slot deklarieren.

Verbindung zu einer Datenbank herstellen
Bevor wir die Klasse „ TableEditor “ verwenden können, müssen wir eine Verbindung zur Datenbank herstellen, die die Tabelle enthält, die wir bearbeiten möchten:
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    if (!createConnection())
        return 1;

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

Die Funktion ` createConnection() ` ist eine Hilfsfunktion, die der Einfachheit halber bereitgestellt wird. Sie ist in der Datei ` connection.h ` definiert, die sich im Beispielverzeichnis ` sql ` befindet (alle Beispiele im Verzeichnis ` sql ` verwenden diese Funktion, um eine Verbindung zu einer Datenbank herzustellen).

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

Die Funktion „ createConnection “ öffnet eine Verbindung zu einer SQLITE-Datenbank im Arbeitsspeicher und erstellt eine Testtabelle. Wenn Sie eine andere Datenbank verwenden möchten, ändern Sie einfach den Code dieser Funktion.

Implementierung der Klasse „TableEditor“

Die Klassenimplementierung besteht aus nur zwei Funktionen: dem Konstruktor und dem Slot „ submit() “. Im Konstruktor erstellen und passen wir das Datenmodell sowie die verschiedenen Fensterelemente an:

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"));

Zunächst erstellen wir das Datenmodell und legen die SQL-Datenbanktabelle fest, auf der das Modell arbeiten soll. Beachten Sie, dass die Funktion „ QSqlTableModel::setTable()“ keine Daten aus der Tabelle auswählt, sondern lediglich deren Feldinformationen abruft. Aus diesem Grund rufen wir später die Funktion „ QSqlTableModel::select()“ auf, um das Modell mit Daten aus der Tabelle zu füllen. Die Auswahl kann durch die Angabe von Filtern und Sortierbedingungen angepasst werden (weitere Details finden Sie in der Dokumentation zur Klasse „ QSqlTableModel “).

Außerdem legen wir die Bearbeitungsstrategie des Modells fest. Die Bearbeitungsstrategie bestimmt, wann die vom Benutzer in der Ansicht vorgenommenen Änderungen tatsächlich auf die Datenbank angewendet werden. Da wir die Änderungen in der Tabellenansicht (d. h. im Modell) zwischenspeichern möchten, bis der Benutzer sie explizit übermittelt, wählen wir die Strategie „ QSqlTableModel::OnManualSubmit “. Die Alternativen sind „ QSqlTableModel::OnFieldChange “ und „ QSqlTableModel::OnRowChange “.

Abschließend richten wir die in der Kopfzeile der Ansicht angezeigten Beschriftungen mithilfe der Funktion ` setHeaderData()` ein, die das Modell von der Klasse ` QSqlQueryModel ` erbt.

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

Anschließend erstellen wir eine Tabellenansicht. Die Klasse ` QTableView ` bietet eine Standard-Modell/Ansicht-Implementierung einer Tabellenansicht, d. h., sie implementiert eine Tabellenansicht, die Elemente aus einem Modell anzeigt. Sie ermöglicht es dem Benutzer außerdem, die Elemente zu bearbeiten und die Änderungen im Modell zu speichern. Um eine schreibgeschützte Ansicht zu erstellen, setzen Sie das entsprechende Flag mithilfe der Eigenschaft ` editTriggers `, die die Ansicht von der Klasse ` QAbstractItemView ` erbt.

Damit die Ansicht unsere Daten anzeigt, übergeben wir unser Modell mithilfe der Funktion ` setModel()` an die Ansicht.

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

Die Schaltflächen von ` TableEditor` sind reguläre ` QPushButton `-Objekte. Wir fügen sie einer Schaltflächenbox hinzu, um sicherzustellen, dass die Schaltflächen in einem Layout dargestellt werden, das dem aktuellen Widget-Stil entspricht. Der Grund dafür ist, dass Dialoge und Meldungsfelder Schaltflächen typischerweise in einem Layout darstellen, das den Schnittstellenrichtlinien der jeweiligen Plattform entspricht. Unterschiedliche Plattformen weisen zwangsläufig unterschiedliche Layouts für ihre Dialoge auf. Die „ QDialogButtonBox “ ermöglicht es einem Entwickler, Schaltflächen hinzuzufügen, und verwendet automatisch das für die Desktop-Umgebung des Benutzers geeignete Layout.

Die meisten Schaltflächen in einem Dialog folgen bestimmten Rollen. Beim Hinzufügen einer Schaltfläche zu einer Schaltflächenbox mithilfe der Funktion ` addButton() ` muss die Rolle der Schaltfläche mithilfe der Enumeration ` QDialogButtonBox::ButtonRole ` angegeben werden. Alternativ stellt ` QDialogButtonBox ` mehrere Standardschaltflächen bereit (z. B. ` OK`, ` Cancel`, ` Save`), die Sie verwenden können. Diese sind als Flags vorhanden, sodass Sie sie im Konstruktor miteinander verknüpfen können.

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

Wir verbinden die Schaltfläche „ Quit “ mit dem Slot „ close()“ des Tabelleneditors und die Schaltfläche „ Submit “ mit unserem privaten Slot „ submit() “. Der letztgenannte Slot übernimmt die Datenübertragung. Schließlich verbinden wir die Schaltfläche „ Revert “ mit dem Slot „ revertAll()“ unseres Modells, wodurch alle ausstehenden Änderungen rückgängig gemacht werden (d. h., die ursprünglichen Daten werden wiederhergestellt).

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

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

Abschließend fügen wir die Schaltflächenbox und die Tabellenansicht zu einem Layout hinzu, fügen das Layout in das Tabelleneditor-Widget ein und legen den Fenstertitel des Editors fest.

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

Der Slot „ submit() “ wird immer dann aufgerufen, wenn der Benutzer auf die Schaltfläche „ Submit “ klickt, um seine Änderungen zu speichern.

Zunächst starten wir mithilfe der Funktion ` QSqlDatabase::transaction()` eine Transaktion in der Datenbank. Eine Datenbanktransaktion ist eine Einheit der Interaktion mit einem Datenbankmanagementsystem oder einem ähnlichen System, die unabhängig von anderen Transaktionen auf kohärente und zuverlässige Weise behandelt wird. Ein Zeiger auf die verwendete Datenbank kann mithilfe der Funktion ` QSqlTableModel::database()` abgerufen werden.

Anschließend versuchen wir, alle ausstehenden Änderungen, d. h. die geänderten Elemente des Modells, zu übermitteln. Tritt kein Fehler auf, führen wir die Transaktion mithilfe der Funktion ` QSqlDatabase::commit()` in der Datenbank ab (beachten Sie, dass diese Funktion bei einigen Datenbanken nicht funktioniert, wenn in der Datenbank ein aktiver ` QSqlQuery ` vorliegt). Andernfalls führen wir mit der Funktion ` QSqlDatabase::rollback()` ein Rollback der Transaktion durch und zeigen dem Benutzer eine Warnung an.

Siehe auch:

Eine vollständige Liste der Qt SQL -Datenbankklassen sowie die Dokumentation zur Model/View-Programmierung.

Beispielprojekt auf 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.