Qt 之 Relational Table Model Example 解析

来源:互联网 发布:牙疼怎么办知乎 编辑:程序博客网 时间:2024/05/18 00:36

总体概述

Relational Table Model Example 例子用到的技术点主要是数据库连接的建立,数据库相关参数的设置,如何执行结构化查询语言(SQL),数据库外键的使用,模型视图框架的使用等等。

代码解析

int main(int argc, char *argv[]){    QApplication app(argc, argv);    if (!createConnection())        return 1;    createRelationalTables();    QSqlRelationalTableModel model;    initializeModel(&model);    QTableView *view = createView(QObject::tr("Relational Table Model"), &model);    view->show();    return app.exec();}
从主函数可以清晰的看到整个程序的结构流程:首先,创建一个数据库连接用于执行SQL和获取数据填充到数据库模型;其次,执行SQL创建三张关系表;接着,初始化数据库模型;最后,创建视图用于显示填充到模型中的数据。

*创建数据库连接
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;    }        return true;}
Qt该例子的createConnection()在打开数据库之后又使用查询对象创建几张表并插入相关数据,实则与该例子没有什么关系,所以这里略去。addDatabase()指定了数据库连接使用的驱动类型是sqlite的驱动(QSQLITE),没有指定数据库连接名(第二个参数)表示使用Qt默认的连接名;setDatabaseName()设置数据库连接将作用的数据库,Qt自带的例子直接将库表建立在内存中,为了方便用工具查看数据库里面的数据我指定为工程目录下的一个名为mytest.db的数据库磁盘文件。如下图:

如果工程目录下事先已有该文件则直接使用已有的文件,如果没有则创建指定名称的数据库文件。

*创建关系表并插入数据
void createRelationalTables(){    QSqlQuery query;    query.exec("create table employee(id int primary key, name varchar(20), city int, country int)");    query.exec("insert into employee values(1, 'Espen', 5000, 47)");    query.exec("insert into employee values(2, 'Harald', 80000, 49)");    query.exec("insert into employee values(3, 'Sam', 100, 1)");    query.exec("create table city(id int, name varchar(20))");    query.exec("insert into city values(100, 'San Jose')");    query.exec("insert into city values(5000, 'Oslo')");    query.exec("insert into city values(80000, 'Munich')");    query.exec("create table country(id int, name varchar(20))");    query.exec("insert into country values(1, 'USA')");    query.exec("insert into country values(47, 'Norway')");    query.exec("insert into country values(49, 'Germany')");}
employee表:
city表:
country表:

employee表中的city和country字段使用的是城市和国家的编号(对应于city表和country表中的id字段),但是这样直接显示employee表显然不是常人可以理解的。

*初始化数据库模型
void initializeModel(QSqlRelationalTableModel *model){//! [0]    model->setTable("employee");//! [0]    model->setEditStrategy(QSqlTableModel::OnManualSubmit);//! [1]    model->setRelation(2, QSqlRelation("city", "id", "name"));//! [1] //! [2]    model->setRelation(3, QSqlRelation("country", "id", "name"));//! [2]//! [3]    model->setHeaderData(0, Qt::Horizontal, QObject::tr("ID"));    model->setHeaderData(1, Qt::Horizontal, QObject::tr("Name"));    model->setHeaderData(2, Qt::Horizontal, QObject::tr("City"));    model->setHeaderData(3, Qt::Horizontal, QObject::tr("Country"));//! [3]    model->select();}
为了解决直接显示城市和国家编号造成的难以理解的问题,将employee表的city(第二个)字段和country(第三个)字段设置为city表id字段的外键和country表id字段的外键;setRelation()做的就是这个事情,并且还指定了将显示给用户的是两张表中的name字段。setTable()指定该模型操作的表为employee表,不会从表中查询数据(select()做的事),而只是获取表的字段信息。setEditStrategy()指定了编辑策略为手动提交(OnManualSubmit:所有的的更改都会在模型中缓存直到调用submitAll()或者revertAll(),这个例子没有调用这两个函数的任意一个所以在模型上的任何更改实际上都没有应用到数据库中;OnFieldChange会立即将在模型上做的所有更改应用到数据库中;OnRowChange则是在你选择了不同行的时候将更改应用到数据库,很多数据库工具都是采取这种编辑策略的哦;setHeaderData()设置模型的表头标签要显示的文本信息(顺带提下代码注释中的! [0]是用于生成Qt的帮助文档用额没有实际意义)。

*创建模型关联的视图
QTableView *createView(const QString &title, QSqlTableModel *model){//! [4]    QTableView *view = new QTableView;    view->setModel(model);    view->setItemDelegate(new QSqlRelationalDelegate(view));//! [4]    view->setWindowTitle(title);    return view;}
setModel()将指定模型绑定到视图上;setItemDelegate()指定一个匿名的Qt默认实现的关系数据库委托;setWindowTitle()设置窗口标题。

运行结果如下图:
对比employee表的原始数据和显示出来的数据就可以理解外键的作用和如果使用Qt提供的数据库相关的C++类来实现相关功能。

示例代码可在Qt Creator的欢迎界面的示例中找到~