缓存SQL表
The Cached Table example shows how a table view can be used to access a database, caching any changes to the data until the user explicitly submits them using a push button.
本例由一个类组成,TableEditor
,它是一个自定义对话框小部件,允许用户修改数据库中存储的数据。我们首先将回顾类定义和如何使用该类,然后我们将查看实现。
TableEditor 类定义
TableEditor
类继承自<(QtWidget.html)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.html)QTableView提供数据。该类提供了一个可编辑的数据模型,使得能够从单个表读取和写入数据库记录。它是在更底层的(QSqlQuery.html)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 Class Implementation
类实现由仅包含两个函数组成,构造函数和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。
最后,我们使用模型从 QSqlQueryModel 类继承的 setHeaderData() 函数来设置在视图标题中显示的标签。
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 对象。我们将它们添加到按钮框中,以确保按钮按照当前小部件样式呈现合适的布局。这样做的原因是,对话框和消息框通常按照该平台界面准则呈现按钮。不同平台对对话框的布局各不相同。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()函数回滚事务并向用户发出警告。
© 2024 Qt公司有限公司。本文件中包含的文档贡献归其各自所有者所有。所提供的文档是根据自由软件基金会发布的GNU自由文档许可证版本1.3的条款许可的。Qt及其相关徽标是世界各地芬兰和/或其他国家Qt公司有限公司的商标。所有其他商标归其各自所有者所有。