展示了如何使用表视图来访问数据库,缓存对数据的任何更改,直到用户使用按钮明确提交这些更改
该示例由一个类TableEditor组成,TableEditor是一个自定义对话框小部件,允许用户修改存储在数据库中的数据
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类可用于向视图类(如QTableView)提供数据。QSqlTableModel类提供了一个可编辑的数据模型,使得从单个表中读写数据库记录成为可能。它建立在较低级别的SqlQuery类之上,该类提供了执行和操作SQL语句的方法。
另外还展示如何使用表视图来缓存对数据的任何更改,直到明确请求提交它们。为此,我们需要在模型和编辑器按钮之外声明一个submit()槽函数
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::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::setable()函数不会从表中选择数据,它只获取它的字段信息,稍后调用QSqlTableModel::select()函数,用表中的数据填充模型,可以通过指定过滤器和排序条件来定制选择
我们还设置了模型的编辑策略,编辑策略规定了用户在视图中所做的更改实际应用于数据库的时间,我们希望在表视图(即模型)中缓存更改,直到用户显式提交它们,因此我们选择了QSqlTableModel::OnManualSubmit策略,另外还有:
QSqlTableModel::OnFieldChange
QSqlTableModel::OnRowChange
最后,我们使用模型从QSqlQueryModel类继承的setHeaderData()函数设置视图标题中显示的标签
QTableView *view = new QTableView;
view->setModel(model);
view->resizeColumnsToContents();
然后我们创建一个表视图view,QTableView类提供了表视图的默认模型/视图实现,它实现了一个显示模型的表视图,它还允许用户编辑项目,将更改存储在模型中,若要创建只读视图,请使用从QAbstractItemView类继承的视图的editTriggers属性设置适当的标志
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中的三个按钮是常规的buttons对象,我们将它们添加到按钮框中,以确保按钮以适合当前小部件样式的布局呈现,QDialogButtonBox允许开发人员向其中添加按钮,并将自动为用户的桌面环境使用适当的布局
对话框的大多数按钮遵循特定的角色,使用addButton()函数向按钮框添加按钮时,必须使用QDialogButtonBox::ButtonRole枚举指定按钮的角色,或者QDialogButtonBox提供了几个您可以使用的标准按钮(例如,确定、取消、保存),它们作为标志存在,因此您可以在构造函数中对它们进行OR运算
connect(submitButton, &QPushButton::clicked, this, &TableEditor::submit);
connect(revertButton, &QPushButton::clicked, model, &QSqlTableModel::revertAll);
connect(quitButton, &QPushButton::clicked, this, &TableEditor::close);
我们将“退出”按钮连接到表格编辑器的close()插槽,将“提交”按钮连接到我们的私有Submit()插槽。后一个插槽将负责数据事务。最后,我们将“恢复”按钮连接到模型的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()槽
首先,我们使用QSqlDatabase::transaction()函数在数据库上开始一个事务。数据库事务是与数据库管理系统或类似系统交互的一个单元,以一种连贯可靠的方式独立于其他事务进行处理。可以使用QSqlTableModel::database()函数获得指向已用数据库的指针
然后,我们尝试提交所有待定的更改,如果没有出现错误,我们就使用SqlDatabase::commit()函数将事务提交给数据库。否则,我们使用QSqlDatabase::rollback()函数执行事务的回滚,并向用户发出警告
#include
#include "connection.h"
#include "tableeditor.h"
//! [0]
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
if (!createConnection())
return 1;
TableEditor editor("person");
editor.show();
return app.exec();
}
//! [0]
#ifndef TABLEEDITOR_H
#define TABLEEDITOR_H
#include
QT_BEGIN_NAMESPACE
class QDialogButtonBox;
class QPushButton;
class QSqlTableModel;
QT_END_NAMESPACE
//! [0]
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;
};
//! [0]
#endif
#include
#include
#include "tableeditor.h"
//! [0]
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"));
//! [0] //! [1]
QTableView *view = new QTableView;
view->setModel(model);
view->resizeColumnsToContents();
//! [1]
//! [2]
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);
//! [2]
//! [3]
connect(submitButton, &QPushButton::clicked, this, &TableEditor::submit);
connect(revertButton, &QPushButton::clicked, model, &QSqlTableModel::revertAll);
connect(quitButton, &QPushButton::clicked, this, &TableEditor::close);
//! [3]
//! [4]
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addWidget(view);
mainLayout->addWidget(buttonBox);
setLayout(mainLayout);
setWindowTitle(tr("Cached Table"));
}
//! [4]
//! [5]
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()));
}
}
//! [5]
#ifndef CONNECTION_H
#define CONNECTION_H
#include
#include
#include
#include
/*
This file defines a helper function to open a connection to an
in-memory SQLITE database and to create a test table.
If you want to use another database, simply modify the code
below. All the examples in this directory use this function to
connect to a database.
*/
//! [0]
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;
}
//! [0]
#endif