缓存 SQL 表
缓存表示例展示了如何使用表视图访问数据库,缓存对数据的任何更改,直到用户使用推送按钮明确提交这些更改。
该示例包含一个单独的类TableEditor
,它是一个自定义对话窗口部件,允许用户修改存储在数据库中的数据。我们将首先回顾该类的定义以及如何使用该类,然后再看看该类的实现。
TableEditor 类定义
TableEditor
类继承于QWidget ,使表格编辑器部件成为一个顶层对话窗口。
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; };
TableEditor
构造函数需要两个参数:第一个参数是TableEditor
对象将操作的数据库表的引用。另一个是指向父窗口部件的指针,并传递给基类构造函数。
请注意QSqlTableModel 变量声明:正如我们将在本例中看到的,QSqlTableModel 类可用于为QTableView 等视图类提供数据。QSqlTableModel 类提供了一个可编辑的数据模型,可以从一个表中读写数据库记录。它建立在低级的QSqlQuery 类之上,后者提供了执行和操作 SQL 语句的方法。
我们还将展示如何使用表视图来缓存对数据的任何更改,直到用户明确要求提交这些更改。因此,除了模型和编辑器按钮外,我们还需要声明一个submit()
插槽。
连接数据库 |
---|
在使用TableEditor 类之前,我们必须创建一个与包含要编辑的表的数据库的连接:int main(int argc, char *argv[]) { QApplication app(argc, argv); if (!createConnection()) return 1; TableEditor editor("person"); editor.show(); return app.exec(); }
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; }
|
TableEditor 类的实现
类的实现只包括两个函数,即构造函数和submit()
槽。在构造函数中,我们创建并自定义数据模型和各种窗口元素:
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"));
首先,我们创建数据模型,并设置希望模型运行的 SQL 数据库表。请注意,QSqlTableModel::setTable() 函数不会从表中选择数据,它只会获取字段信息。因此,我们稍后会调用QSqlTableModel::select() 函数,用表中的数据填充模型。可以通过指定筛选器和排序条件来自定义选择(详情请查看QSqlTableModel 类文档)。
我们还设置了模型的编辑策略。编辑策略决定了用户在视图中所做的更改何时实际应用到数据库。由于我们希望在用户明确提交之前缓存表视图(即模型)中的更改,因此我们选择QSqlTableModel::OnManualSubmit 策略。其他选择是QSqlTableModel::OnFieldChange 和QSqlTableModel::OnRowChange 。
最后,我们使用setHeaderData() 函数设置视图标题中显示的标签,该函数由模型继承自QSqlQueryModel 类。
QTableView *view = new QTableView; view->setModel(model); view->resizeColumnsToContents();
然后,我们创建表格视图。QTableView 类提供了表格视图的默认模型/视图实现,也就是说,它实现了显示来自模型的项目的表格视图。它还允许用户编辑项目,并将更改存储在模型中。要创建只读视图,可使用视图继承自QAbstractItemView 类的editTriggers 属性设置适当的标记。
为了让视图显示我们的数据,我们使用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);
TableEditor
的按钮是普通的QPushButton 对象。我们将它们添加到按钮框中,以确保按钮以适合当前 widget 风格的布局显示。这样做的理由是,对话框和消息框中的按钮布局通常符合该平台的界面指南。QDialogButtonBox 允许开发人员添加按钮,并会自动使用适合用户桌面环境的布局。
对话框的大多数按钮都遵循一定的作用。使用addButton() 函数向按钮框添加按钮时,必须使用QDialogButtonBox::ButtonRole 枚举指定按钮的角色。另外,QDialogButtonBox 也提供了几个标准按钮(如OK,Cancel,Save )供您使用。它们以标志的形式存在,因此您可以在构造函数中将它们连在一起。
connect(submitButton, &QPushButton::clicked, this, &TableEditor::submit); connect(revertButton, &QPushButton::clicked, model, &QSqlTableModel::revertAll); connect(quitButton, &QPushButton::clicked, this, &TableEditor::close);
我们将Quit 按钮连接到表格编辑器的close() 插槽,将Submit 按钮连接到我们的私有submit()
插槽。后者将负责数据交易。最后,我们将Revert 按钮连接到模型的revertAll() 插槽,还原所有待处理的更改(即恢复原始数据)。
QHBoxLayout *mainLayout = new QHBoxLayout; mainLayout->addWidget(view); mainLayout->addWidget(buttonBox); setLayout(mainLayout); setWindowTitle(tr("Cached Table")); }
最后,我们将按钮框和表格视图添加到布局中,将布局安装到表格编辑器部件上,并设置编辑器的窗口标题。
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())); } }
每当用户点击Submit 按钮保存更改时,就会调用submit()
槽。
首先,我们使用QSqlDatabase::transaction() 函数开始数据库事务。数据库事务是与数据库管理系统或类似系统交互的一个单元,它以一种独立于其他事务的连贯、可靠的方式进行处理。使用QSqlTableModel::database() 函数可以获得所使用数据库的指针。
然后,我们尝试提交所有待处理的更改,即模型的修改项。如果没有错误发生,我们就使用QSqlDatabase::commit() 函数将事务提交到数据库(请注意,在某些数据库中,如果数据库上有一个活动的QSqlQuery ,该函数将不起作用)。否则,我们将使用QSqlDatabase::rollback() 函数执行事务回滚,并向用户发出警告。
© 2025 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.