您的位置:首页 > 编程语言 > Qt开发

Qt 之 Cached Table Example 解析

2017-09-15 18:35 971 查看

总体概述



 Cached Table Example 使用了Qt的 模型/视图 框架,数据库模型采用QSqlTableModel ,视图采用 QTableView。界面布局采用一个水平布局和一个垂直布局(QDialogButtonBox 自带)。

代码解析

class TableEditor : public QWidget
{
Q_OBJECT

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

private slots:
void submit();

private:
QPushButton *submitButton;
QPushButton *revertButton;
QPushButton *quitButton;
QDialogButtonBox *buttonBox;
QSqlTableModel *model;
};
TableEdit类继承自QWidget,类声明中把用到的控件和表格模型都声明成指针成员。构造函数带一个表名引用tableName和一个父控件指针parent。QSqlTableModel提供一个可编辑的数据模型,通过这个模型可以从一个单一表读写数据库记录。QSqlTableModel是建立在底层的QSqlQuery之上,QSqlQuery提供执行和操作SQL语句的方法。在视图对表格模型所做的更改都会被缓存直到用户显示地要求提交这些更改(submit())。出于这个原因,定义槽函数submit()用于相应提交(Submit)按钮应用更改到数据库。

int main(int argc, char *argv[])
{
QApplication app(argc, argv);
if (!createConnection())
return 1;

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

在使用数据库模型进行操作之前,必须先创建一个包含我们要编辑的表的数据库连接。然后创建TableEditor对象并显示。最后,开启Qt的事件循环。

static bool createConnection()
{
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
//db.setDatabaseName(":memory:");
db.setDatabaseName("mytest.db");
if (!db.open()) {
QMessageBox::critical(0, qApp->tr("Cannot open database"),
qApp->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;
}
createConnection()是一个便利的辅助函数,用于创建一个默认的数据库连接。Qt示例中所有的数据库例子都是使用这个默认连接去连接到一个数据库的。为了方便查看数据库数据是否被更改我没有像Qt例子中那样将数据库文件指定在内存中,而是指定一个名为mytest.db的一个磁盘文件。Qt自带例子的addDatabase()函数的第二个参数都没有显示地传入一个数据库连接,表示其使用的是Qt默认的数据库连接,但是实际工程中我们往往不能只使用一个数据库连接。比如你的工程中不止使用一个数据库,如果还是使用一个数据库连接这样使用起来很麻烦,你要在数据库关闭之后,再次打开之前重新设置连接指向的数据库,而实际工程中一般LZ都习惯一个数据库连接只关联到一个数据库。
创建于工程目录下的磁盘文件mytest.db:



使用SQLite Expert Professional 查看person表的数据:



TableEdit 类实现:
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"));
首先,创建数据模型,设置模型要操作的库表。QSqlTableModel::setTable()函数不会从指定的表中查询数据;它只是获取字段的信息。获取和填充数据由之后的QSqlTableModel::select()函数实现。查询可以通过自定义特殊的过滤器和排序条件(QSqlTableModel类文档有详细介绍)。

设置模型的编辑策略。编辑策略暗示用户在视图上做的更改什么时候将实际应用于数据库。QSqlTableModel::OnManualSubmit 策略只有用户显示提交更改才会将缓存在数据库模型中数据应用于数据库。

setHeaderData()设置视图表头标签,这个函数继承自QSqlQueryModel 。

QTableView *view = new QTableView;
view->setModel(model);
view->resizeColumnsToContents();
创建表格视图。QTableView类提供了一个表格视图的默认实现,例如,它实现了一个显示模型项数据的表格视图。同时允许用户去编辑这些项,在模型中缓存更改。创建一个只读的视图,设置从QAbstractItemView 类继承的属性editTriggers 为 QAbstractItemView::NoEditTriggers。

传递创建好的视图给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);
创建一个垂直布局的按钮对话框盒子(QDialogButtonBox),将实例化后的三个按钮添加到按钮对话框盒子中。添加按钮时,必须指定按钮的角色(QDialogButtonBox::ButtonRole)。

connect(submitButton, SIGNAL(clicked()), this, SLOT(submit()));
connect(revertButton, SIGNAL(clicked()), model, SLOT(revertAll()));
connect(quitButton, SIGNAL(clicked()), this, SLOT(close()));
绑定退出(Quit)按钮到对话窗体的close()槽函数,提交(Submit)按钮绑定到私有的槽函数submit()。submit()槽函数将处理数据事务。最后,关联恢复(Revert)按钮到模型的revertAll()槽函数上,恢复所有未决的变更(例如,恢复原始数据)。

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

setWindowTitle(tr("Cached Table"));
最后,添加按钮对话框盒子和表格视图到水平布局中,安装布局到TableEditor控件上并设置窗体的标题。

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() 函数可以获得一个已经在使用的数据库连接(Qt帮助文档说获得一个数据库连接的指针其实有误,database()函数的返回值不是一个数据库连接指针QSqlDatabase*,而是QSqlDatabase)。

然后,尝试提交所有未决的更改,例如,模型的更改项。如果没有错误发生,我们使用QSqlDatabase::commit() 函数提交事务到数据库(注意在一些数据库,如果有一个活跃的(active)的查询(QSqlQuery)在数据库上这个函数将不会工作)。如果提交(submitAll())失败,使用QSqlDatabase::rollback()
函数回滚事务并向用户抛出一个警告。

运行截图:
在视图上更改但不提交:



更改视图中的数据但不提交的话,数据库中的数据并不会被改动。

恢复所有在视图上未决的更改:




revertAll()将会把所有未决的更改恢复到最初的数据。

提交在视图上所做的更改:




提交所做的更改(submitAll())在事务成功被提交(commit())后将应用更改到数据库中。

示例代码可在Qt Creator的欢迎界面的示例中找到~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息