Qt数据库

本文档包括Qt数据库的相关知识
更新时间:2011年7月30日

更新作者:
西南石油大学计算机科学学院
乐程软件工作室--刘红
参考资料:
《Qt Creator系列教程》(作者:www.yafeilinux.com)
包括一部分内容:Qt数据库

一、初始数据库
1、我们来看看Qt里的Qtsql Module(Qt Sql 模块)。
2、模块中,命名空间为:
Namespaces
QSql
Contains miscellaneous identifiers used throughout the Qt SQL library
类群有:
Classes
QSqlDatabase Represents a connection to a database
QSqlDriver Abstract base class for accessing specific SQL databases
QSqlDriverCreator Template class that provides a SQL driver factory for a specific driver type
QSqlDriverCreatorBase The base class for SQL driver factories
QSqlDriverPlugin Abstract base for custom QSqlDriver plugins
QSqlError SQL database error information
QSqlField Manipulates the fields in SQL database tables and views
QSqlIndex Functions to manipulate and describe database indexes
QSqlQuery Means of executing and manipulating SQL statements
QSqlQueryModel Read-only data model for SQL result sets
QSqlRecord Encapsulates a database record
QSqlRelation Stores information about an SQL foreign key
QSqlRelationalDelegate Delegate that is used to display and edit data from a QSqlRelationalTableModel
QSqlRelationalTableModel  Editable data model for a single database table, with foreign key support
QSqlResult Abstract interface for accessing data from specific SQL databases
QSqlTableModel Editable data model for a single database table
总共十六个类。
其中,比较重要的两个类,一个是QSqlDatabase类,另一个是QSqlQuery类。6
3、在开始程序之前,我们讲讲这里有那些变化
在放置头文件的地方,包含QSql模块类#include<QtSql>;
同时,在工程文件(.pro)中需要加入一行代码:QT += sql。

4、QSqlDatabase类
Qt里支持
Driver Type Description
QDB2 IBM DB2
QIBASE Borland InterBase Driver
QMYSQL MySQL Driver
QOCI Oracle Call Interface Driver
QODBC ODBC Driver (includes Microsoft SQL Server)
QPSQL PostgreSQL Driver
QSQLITE SQLite version 3 or above
QSQLITE2 SQLite version 2
QTDS Sybase Adaptive Server
一共九种数据库类型。
而现在我们使用的免费的Qt只提供了SQLite和ODBC数据库的驱动。
SQLite是一个小巧的嵌入式数据库,关于它的介绍你可以自己在网上查找。

5、QSqlQuery类
QSqlQuery类用来执行SQL语句。

6、接下来,我们依靠这两个基本类,来实现一个简单的数据库知识。
添加控制台程序,在main函数里添加后
int main(int argc, char *argv[])
{
      QCoreApplication a(argc, argv);
      QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); //添加数据库驱动
      db.setDatabaseName(":memory:"); //数据库连接命名
      if(!db.open()) //打开数据库
      {
            return false;
      }
      QSqlQuery query; //以下执行相关QSL语句
      query.exec("create table student(id int primary key,name varchar)");
      //新建student表,id设置为主键,还有一个name项
      query.exec("insert into student values(1,’xiaogang’)");
      query.exec("insert into student values(2,’xiaoming’)");
      query.exec("insert into student values(3,’xiaohong’)");
      //向表中插入3条记录
      query.exec("select id,name from student where id >= 2");
      //查找表中id >=2 的记录的id项和name项的值
      while(query.next())          //query.next()指向查找到的第一条记录,然后每次后移一条记录
      {
            int ele0 = query.value(0).toInt();            //query.value(0)是id的值,将其转换为int型
            QString ele1 =query.value(1).toString();
            qDebug() << ele0 <<ele1 ;          //输出两个值
      }

      return a.exec();
}

添加头文件:#include <QtSql>

这个程序在4.7.0版本中运行没成功。

7、像tubor c检测图形驱动一样,我们这里也用代码检测一下,数据库驱动
在mian函数里添加后
int main(int argc, char *argv[])
{
      QCoreApplication a(argc, argv);
      qDebug() << "Available drivers:";
      QStringList drivers = QSqlDatabase::drivers();
      foreach(QString driver, drivers)
      qDebug() << "\t" << driver;
      return a.exec();
}

二、嵌入式数据库(SQLITE)
1、SQLITE是Qt提供的一种进程内数据库,小巧灵活,无须额外安装配置且支持大部分ANSI SQL92标准,是一个轻量级的数据库。

2、下面以控制台程序为例,讲解使用SQLITE数据库完成大批量数据的增删改查四种基本操作,并打印其操作耗时。

①首先添加头文件,并创建一个Qt应用程序对象app,并设置中文显示。
#include <QtSql>
#include <QMessageBox>
QApplication app(argc,argv);
QTextCodec::setCodecFortr(QTextCodec::codecForName("gb18030"));
//这里之前,我们用的是这样代码
QTextCodec::setCodecForTr(QTextCodec::codecForLocale());
//经过比较,没什么大的区别,如果要深究的,我只能说我阅读的是不同的文章,得出的不同代码。后面不做过多的解释,望谅解。

同时记得在.pro文件中添加QT +=sql和QT +=gui。(千万别忘记咯!)

②接下来,在上面代码下面,继续添加QSQLITE驱动名称,并以":memory:"为数据库名,在本地进程中创建一个SQLite数据库。然后使用QSqlQuery类创建数据库表"automobil",该表具有10个字段,后面的操作都针对这个表进行。
具体代码如下:
QSqlDatabase db= QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName(":memory:");
if(!db.open()){
QMessageBox::critical(0,QObject::tr("无法打开数据库,请阅读Qt SQL驱动文档\n"),QObject::tr("退出请按Cancel键"),QMessageBox::Cancel,QMessageBox::NoButton);
return false;
}
QSqlQuery query;
bool bSuccess = query.exec("CREATE TABLE automobil("
"id INT PRIMARY KEY,"
"attribute VARCHAR,"
"type VARCHAR,"
"kind VARCHAR,"
"nation INT,"
"carnumber INT,"
"elevaltor INT,"
"distance INT,"
"oil INT,"
"temperature INT)");
if(bSuccess) qDebug()<<QObject::tr("数据库表创建成功!\n");
else qDebug()<<QObject::tr("数据库表创建失败!\n");
这是运行程序,可以看到:
"数据库表创建成功!
"
的字样,表示数据库创建成功!
③表创建成功之后,我们开始进行相应的查询操作。
这里为了统计,程序运行的时间,我们在程序中添加一个计时器t,然后向表中
QTime t;
t.start();
query.prepare("INSERT INTO automobil"
"(id,attribute,type,kind,nation,"
"carnumber,elevaltor,distance,oil,temperature)"
"VALUES(:id,:attribute,:type,:kind,:nation,"
":carnumber,:elevaltor,:distance,:oil,:temperature)");
long records = 10000;
for(int i=0;i<records;i++){
query.bindValue(0,i);
query.bindValue(1,"四轮");
query.bindValue(2,"轿车");
query.bindValue(3,"富康");
query.bindValue(4,rand()0);
query.bindValue(5,rand()000);
query.bindValue(6,rand()00);
query.bindValue(7,rand() 0000);
query.bindValue(8,rand()R);
query.bindValue(9,rand()0);
bSuccess = query.exec();
if(!bSuccess){
QSqlError lastError = query.lastError();
qDebug() << lastError.driverText()
<<QString(QObject::tr("插入失败"));
qDebug()<<QObject::tr("插入%1条记录,耗时:%2 ms").arg(records).arg(t.elapsed());
//以上为插入操作
④接下来重启计时器t,然后在查询表中刚刚插入的10000条记录,并按id字段的降序排列,以及打印操作耗时。
t.restart();
bSuccess = query.exec("SELECT * FROM automobil ORDER BY id DESC");
if(bSuccess)
qDebug()<<QObject::tr("排序%1条记录,耗时%2ms").arg(records).arg(t.elapsed());

else 
qDebug()<<QObject::tr("排序失败!");

⑤更新操作与插入操作类似,仅仅是使用的SQL语句的不同。这里我们要重启计时器计时。
t.restart();
for(int i=0;i<records;i++){
     query.clear();
     query.prepare(QString("UPDATE automobil SET"
                           "attribute=?,type=?,kind=?,"
"nation=?,carnumber=?,elevaltor=?,"
"distance=?,oil=?,temperature=?"
                                    "WHERE id=%1").arg(i));
               
                  query.bindValue(0,"四轮");
                  query.bindValue(1,"轿车");
                  query.bindValue(2,"富康");
                  query.bindValue(3,rand()0);
                  query.bindValue(4,rand()000);
                  query.bindValue(5,rand()00);
                  query.bindValue(6,rand() 0000);
                  query.bindValue(7,rand()R);
                  query.bindValue(8,rand()0);
                  bSuccess = query.exec();
                  if(!bSuccess){
                              QSqlError lastError = query.lastError();
                              qDebug() << lastError.driverText()
                                          <<QString(QObject::tr("更新失败"));
                        }
            }
            qDebug()<<QObject::tr("更新%1条记录,耗时:%2 ms").arg(records).arg(t.elapsed());
//更新操作在4.7.0中,运行时,宣告失败!我暂不用考虑它。接下来我们看下面的内容。
⑥删除操作
t.restart();
            query.exec("DELETE FROM automobil WHERE id<=1500");
            qDebug()<<QObject::tr("删除1501条记录,耗时%1 ms").arg(t.elapsed());
//删除操作可以在编译器执行

3、接下来,我们以一个QWidget Gui工程,来详细讲解SQL语句。
①SQL即结构化查询语言,是关系数据库的标准语言。我们知道,在Qt中利用QSqlQuery类可以实现了执行SQL语句。
②这里我们讲解四个知识点
分别是:(一,操作SQL语句返回的结果集。
二,在SQL语句中使用变量。三,批处理操作。四,事务操作。)
③工程建好,我们做好准备工作,即添加头文件#include <QSqlDatabase>和
#include <QSqlQuery>;在工程文件(.pro)中添加QT +=sql;
添加C++ Header File ,命名为connection.h ,更改其内容如下:
#ifndef CONNECTION_H
#define CONNECTION_H
#include <QMessageBox>
#include <QSqlDatabase>
#include <QSqlQuery>
static bool createConnection()
{
      QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
      db.setDatabaseName(":memory:");
      if (!db.open()) {
            QMessageBox::critical(0, qApp->tr("Cannot open database"),
                  qApp->tr("Unable to establish a database connection."
                                ), QMessageBox::Cancel);
            return false;
      }
      QSqlQuery query;
      query.prepare("create table student (id int primary key, "
                       "name varchar(20))");
      query.exec();

      query.exec("insert into student values(0, 'first')");
      query.exec("insert into student values(1, 'second')");
      query.exec("insert into student values(2, 'third')");
      query.exec("insert into student values(3, 'fourth')");
      query.exec("insert into student values(4, 'fifth')");
      return true;
}
#endif // CONNECTION_H
这里我们新建了一张新表student,表中的一行就叫做一条记录,一列是一个属性。这个表共有5条记录,id和name两个属性。程序中的“id int primary key”表明id属性是主键,也就是说以后添加记录时,必须有id项。

④下面我们打开widget.ui文件,在设计器中向界面上添加一个Push Button ,和一个Spin Box 。将按钮的文本改为“查询”,然后进入其单击事件槽函数,更改如下。
void Widget::on_pushButton_clicked()
{
      QSqlQuery query;
      query.exec("select * from student");
      while(query.next())
      {
            qDebug() << query.value(0).toInt() << query.value(1).toString();
      }

}
同时记得添加头文件:
#include <QSqlQuery>
#include <QDebug>

运行程序,点击按钮,这时可以看到在输出窗口,表中的所有内容都输出出来了。这表明我们的数据库连接已经成功建立了。
⑤完成连接,我们可以放心大胆的往下,进行了。
先来看看(一,操作SQL语句返回的结果集)

在上面的程序中,我们使用query.exec(“select * from student”);来查询出表中所有的内容。其中“*”号表明查询表中记录的所有属性。这条语句执行完后,我们便获得了相应的执行结果,因为获得的结果可能不止一条记录,所以我们称之为结果集。

结果集其实就是查询到的所有记录的集合。

Qt中,操作结果集的QSqlQuery类函数有:(以下最常用)

seek(int n) :query指向结果集的第n条记录。//起始是0。
first() :query指向结果集的第一条记录。//即n=0的记录
last() :query指向结果集的最后一条记录。

next() :query指向下一条记录,每执行一次该函数,便指向相邻的下一条记录。当第一次执行这个函数时,query便指向了结果集的第一条记录。
previous() :query指向上一条记录,每执行一次该函数,便指向相邻的上一条记录。
record() :获得现在指向的记录。
value(int n) :获得属性的值。其中n表示你查询的第n个属性,比方上面我们使用“select * from student”就相当于“select id, name from student”,那么value(0)返回id属性的值,value(1)返回name属性的值。该函数返回QVariant类型的数据,关于该类型与其他类型的对应关系,可以在帮助中查看QVariant。
at() :获得现在query指向的记录在结果集中的编号。

接下来,我们使用这些函数,来看看它们是不是有这些功能。
修改按钮单击事件槽函数后:
      void Widget::on_pushButton_clicked()
      {
            QSqlQuery query;
            query.prepare("select * from student");
            query.exec();
            qDebug() << "exec next() :";
            if(query.next())
            //开始就先执行一次next()函数,那么query指向结果集的第一条记录
            {
                  int rowNum = query.at();
                  //获取query所指向的记录在结果集中的编号
                  int columnNum = query.record().count();
                  //获取每条记录中属性(即列)的个数
                  int fieldNo = query.record().indexOf("name");
                  //获取”name”属性所在列的编号,列从左向右编号,最左边的编号为0
                  int id = query.value(0).toInt();
                  //获取id属性的值,并转换为int型
                 QString name = query.value(fieldNo).toString();
                  //获取name属性的值
                  qDebug() << "rowNum is : " << rowNum //将结果输出
                              << " id is : " << id
                              << " name is : " << name
                              << " columnNum is : " << columnNum
                              << " fileldNo is: " << fieldNo;
            }
            qDebug() << "exec seek(2) :";
            if(query.seek(2))
            //定位到结果集中编号为2的记录,即第三条记录,因为第一条记录的编号为0
            {
                  qDebug() << "rowNum is : " << query.at()
                              << " id is : " << query.value(0).toInt()
                              << " name is : " << query.value(1).toString();
            }
            qDebug() << "exec last() :";
            if(query.last())
            //定位到结果集中最后一条记录
            {
                  qDebug() << "rowNum is : " << query.at()
                              << " id is : " << query.value(0).toInt()
                              << " name is : " << query.value(1).toString();
            }
      }
记得添加头文件:#include <QSqlRecord>

再来看看(二,在SQL语句中使用变量)
修改按钮单击事件槽函数后:
void Widget::on_pushButton_clicked()
{
                  QSqlQuery query;
                  query.prepare("insert into student (id, name) "
                                       "values (:id, :name)");
                  query.bindValue(0, 5);
                  query.bindValue(1, "sixth");
                  query.exec();
                  //下面输出最后一条记录
                  query.exec("select * from student");
                  query.last();
                  int id = query.value(0).toInt();
                  QString name = query.value(1).toString();
                  qDebug() << id << name;

}

这里我们利用了:id和:name这两个占位符,这是ODBC数据库的表示方法,还有一种Oracle的表示方法就是全部用“?”号。如下:
query.prepare("insert into student (id, name) "
                           "values (?, ?)");
query.bindValue(0, 5);
query.bindValue(1, "sixth");
query.exec();

我们也可以利用addBindValue()函数,这样就可以省去编号,它是按顺序给属性赋值的,如下:
query.prepare("insert into student (id, name) "
                           "values (?, ?)");
query.addBindValue(5);
query.addBindValue("sixth");
query.exec();

当用ODBC的表示方法时,我们也可以将编号用实际的占位符代替,如下:
query.prepare("insert into student (id, name) "
                                 "values (:id, :name)");
query.bindValue(":id", 5);
query.bindValue(":name", "sixth");
query.exec();

下面我们就可以利用绑定操作在SQL语句中使用变量了。
void Widget::on_pushButton_clicked()
{
      QSqlQuery query;
      query.prepare("select name from student where id = ?");
      int id = ui->spinBox->value(); //从界面获取id的值
      query.addBindValue(id); //将id值进行绑定
      query.exec();
      query.next(); //指向第一条记录
      qDebug() << query.value(0).toString();
}
这里我们,我们为了不让spinBox的值发生过大的改变,我们在构造函数里添加一句代码:
ui->spinBox->setRange(0,4);

接着来看看(三,批处理操作)
当要进行多条记录的操作时,我们就可以利用绑定进行批处理
同样,我们修改,按钮单击事件槽函数如下:
void Widget::on_pushButton_clicked()
{
      QSqlQuery q;
      q.prepare("insert into student values (?, ?)");
      QVariantList ints;
      ints << 10 << 11 << 12 << 13;
      q.addBindValue(ints);
      QVariantList names;
      names << "xiaoming" << "xiaoliang" << "xiaogang" << QVariant(QVariant::String);
      //最后一个是空字符串,应与前面的格式相同
     q.addBindValue(names);
      if (!q.execBatch()) //进行批处理,如果出错就输出错误
            qDebug() << q.lastError();
      
      //下面输出整张表
      QSqlQuery query;
      query.exec("select * from student");
      while(query.next())
      {
            int id = query.value(0).toInt();
            QString name = query.value(1).toString();
            qDebug() << id << name;
      }
}
记得添加头文件:#include <QSqlError>

我们在程序中利用列表存储了同一属性的多个值,然后进行了值绑定。最后执行execBatch()函数进行批处理。注意程序中利用QVariant(QVariant::String)来输入空值NULL,因为前面都是QString类型的,所以这里要使用QVariant::String 使格式一致化。

最后我们看看(四,事务操作)

事务是数据库的一个重要功能,所谓事务是用户定义的一个数据库操作序列,这些操作要么全做要么全不做,是一个不可分割的工作单位。

在Qt中用transaction()开始一个事务操作,用commit()函数或rollback()函数进行结束。

commit()表示提交,即提交事务的所有操作。具体地说就是将事务中所有对数据库的更新写回到数据库,事务正常结束。

rollback()表示回滚,即在事务运行的过程中发生了某种故障,事务不能继续进行,系统将事务中对数据库的所有已完成的操作全部撤销,回滚到事务开始时的状态。

例如:
void Widget::on_pushButton_clicked()
{
      if(QSqlDatabase::database().driver()->hasFeature(QSqlDriver::Transactions))
      {       //先判断该数据库是否支持事务操作
            QSqlQuery query;
            if(QSqlDatabase::database().transaction()) //启动事务操作
            {
                  //
                  //下面执行各种数据库操作
                  query.exec("insert into student values (14, 'hello')");
                  query.exec("delete from student where id = 1");
                  //
                  if(!QSqlDatabase::database().commit())
                  {
                        qDebug() << QSqlDatabase::database().lastError(); //提交
                        if(!QSqlDatabase::database().rollback())
                              qDebug() << QSqlDatabase::database().lastError(); //回滚
                  }
            }
            //输出整张表
            query.exec("select * from student");
            while(query.next())
                  qDebug() << query.value(0).toInt() << query.value(1).toString();
      }
}
注:
QSqlDatabase::database()返回程序前面所生成的连接的QSqlDatabase对象。
hasFeature()函数可以查看一个数据库是否支持事务。

嵌入式数据库就讲解到此,一下我们先换个思维来讲解。


三、Qt简便的数据库操作方法:使用QSqlQueryModel类。
1、前面我们讲了,用QSqlQuery类执行SQL语句来操作数据库。其实,Qt为我们提供了更简单的数据库操作和数据显示模型。

它们分别是只读的QSqlQueryModel,操作单表的QSqlTableModel和以及可以支持外键的QSqlRelationalTableModel

我们先来看看QSqlQueryModel类。
2、QSqlQueryModel
以下是它的成员列表:
QSqlQueryModel ( QObject * )
~QSqlQueryModel ()
beginInsertColumns ( const QModelIndex &, int, int )
beginInsertRows ( const QModelIndex &, int, int )
beginMoveColumns ( const QModelIndex &, int, int, const QModelIndex &, int ) : bool
beginMoveRows ( const QModelIndex &, int, int, const QModelIndex &, int ) : bool
beginRemoveColumns ( const QModelIndex &, int, int )
beginRemoveRows ( const QModelIndex &, int, int )
beginResetModel ()
blockSignals ( bool ) : bool
buddy ( const QModelIndex & ) const : QModelIndex
canFetchMore ( const QModelIndex & ) const : bool
changePersistentIndex ( const QModelIndex &, const QModelIndex & )
changePersistentIndexLis t ( const QModelIndexList &, const QModelIndexList & )
childEvent ( QChildEvent * )
children () const : const QObjectList &
clear ()
columnCount ( const QModelIndex & ) const : int
columnsAboutToBeInserted  ( const QModelIndex &, int, int )
columnsAboutToBeMoved ( const QModelIndex &, int, int, const QModelIndex &, int )
columnsAboutToBeRemoved ( const QModelIndex &, int, int )
columnsInserted ( const QModelIndex &, int, int )
columnsMoved ( const QModelIndex &, int, int, const QModelIndex &, int )
columnsRemoved ( const QModelIndex &, int, int )
connect ( const QObject *, const char *, const QObject *, const char *, Qt::ConnectionType ) : bool
connect ( const QObject *, const char *, const char *, Qt::ConnectionType ) const : bool
connectNotify ( const char * )
createIndex ( int, int, void * ) const : QModelIndex
createIndex ( int, int, quint32 ) const : QModelIndex
customEvent ( QEvent * )
d_ptr : QScopedPointer<QObjectData>
data ( const QModelIndex &, int ) const : QVariant
dataChanged ( const QModelIndex &, const QModelIndex & )
deleteLater ()
destroyed ( QObject * )
disconnect ( const QObject *, const char *, const QObject *, const char * ) : bool
disconnect ( const char *, const QObject *, const char * ) : bool
disconnect ( const QObject *, const char * ) : bool
disconnectNotify ( const char * )
dropMimeData ( const QMimeData *, Qt::DropAction, int, int, const QModelIndex & ) : bool
dumpObjectInfo ()
dumpObjectTree ()
dynamicPropertyNames () const : QList<QByteArray>
endInsertColumns ()
endInsertRows ()
endMoveColumns ()
endMoveRows ()
endRemoveColumns ()
endRemoveRows ()
endResetModel ()
event ( QEvent * ) : bool
eventFilter ( QObject *, QEvent * ) : bool
fetchMore ( const QModelIndex & )
findChild ( const QString & ) const : T
findChildren ( const QString & ) const : QList<T>
findChildren ( const QRegExp & ) const : QList<T>
flags ( const QModelIndex & ) const : Qt::ItemFlags
hasChildren ( const QModelIndex & ) const : bool
hasIndex ( int, int, const QModelIndex & ) const : bool
headerData ( int, Qt::Orientation, int ) const : QVariant
headerDataChanged ( Qt::Orientation, int, int )
index ( int, int, const QModelIndex & ) const : QModelIndex
indexInQuery ( const QModelIndex & ) const : QModelIndex
inherits ( const char * ) const : bool
insertColumn ( int, const QModelIndex & ) : bool
insertColumns ( int, int, const QModelIndex & ) : bool
insertRow ( int, const QModelIndex & ) : bool
insertRows ( int, int, const QModelIndex & ) : bool
installEventFilter ( QObject * )
isWidgetType () const : bool
itemData ( const QModelIndex & ) const : QMap<int, QVariant>
killTimer ( int )
lastError () const : QSqlError
layoutAboutToBeChanged ()
layoutChanged ()
match ( const QModelIndex &, int, const QVariant &, int, Qt::MatchFlags ) const : QModelIndexList
metaObject () const : const QMetaObject *
mimeData ( const QModelIndexList & ) const : QMimeData *
mimeTypes () const : QStringList
modelAboutToBeReset ()
modelReset ()
moveToThread ( QThread * )
objectName () const : QString
parent ( const QModelIndex & ) const : QModelIndex
persistentIndexList () const : QModelIndexList
property ( const char * ) const : QVariant
query () const : QSqlQuery
queryChange ()
receivers ( const char * ) const : int
record ( int ) const : QSqlRecord
record () const : QSqlRecord
removeColumn ( int, const QModelIndex & ) : bool
removeColumns ( int, int, const QModelIndex & ) : bool
removeEventFilter ( QObject * )
removeRow ( int, const QModelIndex & ) : bool
removeRows ( int, int, const QModelIndex & ) : bool
reset ()
revert ()
roleNames () const : const QHash<int, QByteArray> &
rowCount ( const QModelIndex & ) const : int
rowsAboutToBeInserted ( const QModelIndex &, int, int )
rowsAboutToBeMoved ( const QModelIndex &, int, int, const QModelIndex &, int )
rowsAboutToBeRemoved ( const QModelIndex &, int, int )
rowsInserted ( const QModelIndex &, int, int )
rowsMoved ( const QModelIndex &, int, int, const QModelIndex &, int )
rowsRemoved ( const QModelIndex &, int, int )
sender () const : QObject *
setData ( const QModelIndex &, const QVariant &, int ) : bool
setHeaderData ( int, Qt::Orientation, const QVariant &, int ) : bool
setItemData ( const QModelIndex &, const QMap<int, QVariant> & ) : bool
setLastError ( const QSqlError & )
setObjectName ( const QString & )
setParent ( QObject * )
setProperty ( const char *, const QVariant & ) : bool
setQuery ( const QSqlQuery & )
setQuery ( const QString &, const QSqlDatabase & )
setRoleNames ( const QHash<int, QByteArray> & )
setSupportedDragActions ( Qt::DropActions )
sibling ( int, int, const QModelIndex & ) const : QModelIndex
signalsBlocked () const : bool
sort ( int, Qt::SortOrder )
span ( const QModelIndex & ) const : QSize
startTimer ( int ) : int
staticMetaObject : const QMetaObject
staticQtMetaObject : const QMetaObject
submit () : bool
supportedDragActions () const : Qt::DropActions
supportedDropActions () const : Qt::DropActions
thread () const : QThread *
timerEvent ( QTimerEvent * )
tr ( const char *, const char *, int ) : QString
trUtf8 ( const char *, const char *, int ) : QString

我们再比对一下,QSqlQuery类的成员列表:
enum BatchExecutionMode
QSqlQuery ( QSqlResult * )
QSqlQuery ( const QString &, QSqlDatabase )
QSqlQuery ( QSqlDatabase )
QSqlQuery ( const QSqlQuery & )
~QSqlQuery ()
addBindValue ( const QVariant &, QSql::ParamType )
at () const : int
bindValue ( const QString &, const QVariant &, QSql::ParamType )
bindValue ( int, const QVariant &, QSql::ParamType )
boundValue ( const QString & ) const : QVariant
boundValue ( int ) const : QVariant
boundValues () const : QMap<QString, QVariant>
clear ()
driver () const : const QSqlDriver *
exec ( const QString & ) : bool
exec () : bool
execBatch ( BatchExecutionMode ) : bool
executedQuery () const : QString
finish ()
first () : bool
isActive () const : bool
isForwardOnly () const : bool
isNull ( int ) const : bool
isSelect () const : bool
isValid () const : bool
last () : bool
lastError () const : QSqlError
lastInsertId () const : QVariant
lastQuery () const : QString
next () : bool
nextResult () : bool
numRowsAffected () const : int
numericalPrecisionPolicy  () const : QSql::NumericalPrecisionPolicy
prepare ( const QString & ) : bool
previous () : bool
record () const : QSqlRecord
result () const : const QSqlResult *
seek ( int, bool ) : bool
setForwardOnly ( bool )
setNumericalPrecisionPol icy ( QSql::NumericalPrecisionPolicy  )
size () const : int
value ( int ) const : QVariant
operator= ( const QSqlQuery & ) : QSqlQuery &

其实,有很多相似的地方,这里我们就不继续深究了。

3、我们先用个简单的例子来,举例其是怎样操作数据库的。

先新建一个QWidget Gui工程,添加一个.h文件,命名为:database.h。

database.h中,修改过后为:
#ifndef DATABASE_H
#define DATABASE_H
#include <QSqlDatabase>
#include <QSqlQuery>
static bool createConnection()
{
      QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
      db.setDatabaseName("database.db");
      if(!db.open()) return false;
      QSqlQuery query;
      query.exec("create table student (id int primary key, name vchar)");
      query.exec("insert into student values (0,'yafei0')");
      query.exec("insert into student values (1,'yafei1')");
      query.exec("insert into student values (2,'yafei2')");
      return true;
}

#endif // DATABASE_H
这里我们使用了db.setDatabaseName(“database.db”); ,我们没有再使用以前的内存数据库,而是使用了真实的文件,这样后面对数据库进行的操作就能保存下来了。

接着在main函数里,
添加代码:
if(!createConnection())
            return 1;
添加头文件:
#include "database.h"

然后我们添加一个按钮,并添加它的单击事件槽函数,更改如下:
void Widget::on_pushButton_clicked()
{
      QSqlQueryModel *model = new QSqlQueryModel;
      model->setQuery("select * from student");
      model->setHeaderData(0, Qt::Horizontal, tr("id"));
      model->setHeaderData(1, Qt::Horizontal, tr("name"));
      QTableView *view = new QTableView;
      view->setModel(model);
      view->show();
}
添加头文件:
#include <QSqlQueryModel>
#include <QTableView>
#include "database.h"

这里我们新建了QSqlQueryModel类对象model,并用setQuery()函数执行了SQL语句“(“select * from student”);”用来查询整个student表的内容。

可以看到,该类并没有完全避免SQL语句。然后我们设置了表中属性显示时的名字。最后我们建立了一个视图view,并将这个model模型关联到视图中,这样数据库中的数据就能在窗口上的表中显示出来了。



接下来,我们用它来接受数据库的数据

在按钮的单击事件槽函数中,我们添加代码如下:
int column = model->columnCount(); //获得列数
      int row = model->rowCount();      // 获得行数
      QSqlRecord record = model->record(1); //获得一条记录
      QModelIndex index = model->index(1,1);    //获得一条记录的一个属性的值
      qDebug() << "column num is:" << column << endl
                        << "row num is:" << row << endl
                        <<"the second record is:" << record << endl
                        << "the data of index(1,1) is:"<< index.data();
添加头文件:
#include <QSqlRecord>
#include <QModelIndex>
#include <QDebug>

另一种方法是使用前面介绍过的query执行SQL语句
在按钮单击事件槽函数里添加:
      QSqlQuery query = model->query();
      query.exec("select name from student where id = 2 ");
      query.next();
      qDebug() << query.value(0).toString();
同样可以输出数据库中的数据信息。



接着我们作修改动作

此时,我们更改单击事件槽函数为:
void Widget::on_pushButton_clicked()
{
      QSqlQueryModel *model = new QSqlQueryModel;
      model->setQuery("select * from student");
      model->setHeaderData(0, Qt::Horizontal, tr("id"));
      model->setHeaderData(1, Qt::Horizontal, tr("name"));
      QTableView *view = new QTableView;
      view->setModel(model);
      view->show();
      QSqlQuery query = model->query();
      query.exec("insert into student values (10,'yafei10')");
      //插入一条记录

      query.exec("insert into student values (20,'yafei20')");
      //插入一条记录
      model->setQuery("select * from student"); //再次查询整张表
      view->show(); //再次进行显示  
}

4、自定义QSqlQueryModel子类。
刚开始我们就讲到,这个模型默认是只读的,所以我们在窗口上并不能对表格中的内容进行修改。

但是我们可以创建自己的模型,然后按照我们自己的意愿来显示数据和修改数据。要想使其可读写,需要自己的类继承自QSqlQueryModel,并且重写setData() 和 flags() 两个函数。如果我们要改变数据的显示,就要重写data() 函数。

这里我们举例让student表的id属性列显示红色,name属性列可编辑。

首先我们在工程中添加C++ Class,然后Class name设为MySqlQueryModel,Base Class设为QSqlQueryModel。

接着将mysqlquerymodel.h修改为:

class MySqlQueryModel : public QSqlQueryModel
{
public:
      MySqlQueryModel();
      //下面三个函数都是虚函数,我们对其进行重载
      Qt::ItemFlags flags(const QModelIndex &index) const;
      bool setData(const QModelIndex &index, const QVariant &value, int role);
      QVariant data(const QModelIndex &item, int role=Qt::DisplayRole) const;
      //
private:
      bool setName(int studentId, const QString &name);
      void refresh();
};


然后将mysqlquerymodel.cpp文件更改为:
#include "mysqlquerymodel.h"
#include <QSqlQuery>
#include <QColor>

MySqlQueryModel::MySqlQueryModel()
{
}
Qt::ItemFlags MySqlQueryModel::flags(
            const QModelIndex &index) const //返回表格是否可更改的标志
{
      Qt::ItemFlags flags = QSqlQueryModel::flags(index);
      if (index.column() == 1) //第二个属性可更改
            flags |= Qt::ItemIsEditable;
      return flags;
}
bool MySqlQueryModel::setData(const QModelIndex &index, const QVariant &value, int )
            //添加数据
{
      if (index.column() < 1 || index.column() > 2)
            return false;
      QModelIndex primaryKeyIndex = QSqlQueryModel::index(index.row(), 0);
      int id = data(primaryKeyIndex).toInt(); //获取id号
      clear();
      bool ok;
      if (index.column() == 1) //第二个属性可更改
            ok = setName(id, value.toString());
      refresh();
      return ok;
}
void MySqlQueryModel::refresh() //更新显示
{
      setQuery("select * from student");
      setHeaderData(0, Qt::Horizontal, QObject::tr("id"));
      setHeaderData(1, Qt::Horizontal, QObject::tr("name"));
}
bool MySqlQueryModel::setName(int studentId, const QString &name) //添加name属性的值
{
      QSqlQuery query;
      query.prepare("update student set name = ? where id = ?");
      query.addBindValue(name);
      query.addBindValue(studentId);
      return query.exec();
}
QVariant MySqlQueryModel::data(const QModelIndex &index, int role) const
            //更改数据显示样式
{
      QVariant value = QSqlQueryModel::data(index, role);
      if (role == Qt::TextColorRole && index.column() == 0)
            return qVariantFromValue(QColor(Qt::red)); //第一个属性的字体颜色为红色
      return value;
}

最后修改widget.cpp文件:
添加头文件:#include "mysqlquerymodel.h"
按钮单击事件槽函数:
void Widget::on_pushButton_clicked()
{
      QSqlQueryModel *model = new QSqlQueryModel;
      model->setQuery("select * from student");
      model->setHeaderData(0, Qt::Horizontal, tr("id"));
      model->setHeaderData(1, Qt::Horizontal, tr("name"));
      QTableView *view = new QTableView;
      view->setModel(model);
      view->show();
      MySqlQueryModel *myModel = new MySqlQueryModel; //创建自己模型的对象
      myModel->setQuery("select * from student");
      myModel->setHeaderData(0, Qt::Horizontal, tr("id"));
      myModel->setHeaderData(1, Qt::Horizontal, tr("name"));
      QTableView *view1 = new QTableView;
      view1->setWindowTitle("mySqlQueryModel"); //修改窗口标题
      view1->setModel(myModel);
      view1->show();
}

经过以上,我们可以看出Qt的强大了。

四、QSqlTableModel类(继承于QSqlQueryModel)
1、虽然只读的QSqlQueryModel也可以使其可编辑,但是很麻烦。
所以Qt提供了操作单表的QSqlTableModel,如果我们需要对表的内容进行修改,那么我们就可以直接使用这个类。

2、QSqlTableModel,该类提供了一个可读写单张SQL表的可编辑数据模型。
我们先来看看这个类的成员:
enum EditStrategy
QSqlTableModel ( QObject *, QSqlDatabase )
~QSqlTableModel ()
beforeDelete ( int )
beforeInsert ( QSqlRecord & )
beforeUpdate ( int, QSqlRecord & )
beginInsertColumns ( const QModelIndex &, int, int )
beginInsertRows ( const QModelIndex &, int, int )
beginMoveColumns ( const QModelIndex &, int, int, const QModelIndex &, int ) : bool
beginMoveRows ( const QModelIndex &, int, int, const QModelIndex &, int ) : bool
beginRemoveColumns ( const QModelIndex &, int, int )
beginRemoveRows ( const QModelIndex &, int, int )
beginResetModel ()
blockSignals ( bool ) : bool
buddy ( const QModelIndex & ) const : QModelIndex
canFetchMore ( const QModelIndex & ) const : bool
changePersistentIndex ( const QModelIndex &, const QModelIndex & )
changePersistentIndexLis t ( const QModelIndexList &, const QModelIndexList & )
childEvent ( QChildEvent * )
children () const : const QObjectList &
clear ()
columnCount ( const QModelIndex & ) const : int
columnsAboutToBeInserted  ( const QModelIndex &, int, int )
columnsAboutToBeMoved ( const QModelIndex &, int, int, const QModelIndex &, int )
columnsAboutToBeRemoved ( const QModelIndex &, int, int )
columnsInserted ( const QModelIndex &, int, int )
columnsMoved ( const QModelIndex &, int, int, const QModelIndex &, int )
columnsRemoved ( const QModelIndex &, int, int )
connect ( const QObject *, const char *, const QObject *, const char *, Qt::ConnectionType ) : bool
connect ( const QObject *, const char *, const char *, Qt::ConnectionType ) const : bool
connectNotify ( const char * )
createIndex ( int, int, void * ) const : QModelIndex
createIndex ( int, int, quint32 ) const : QModelIndex
customEvent ( QEvent * )
d_ptr : QScopedPointer<QObjectData>
data ( const QModelIndex &, int ) const : QVariant
dataChanged ( const QModelIndex &, const QModelIndex & )
database () const : QSqlDatabase
deleteLater ()
deleteRowFromTable ( int ) : bool
destroyed ( QObject * )
disconnect ( const QObject *, const char *, const QObject *, const char * ) : bool
disconnect ( const char *, const QObject *, const char * ) : bool
disconnect ( const QObject *, const char * ) : bool
disconnectNotify ( const char * )
dropMimeData ( const QMimeData *, Qt::DropAction, int, int, const QModelIndex & ) : bool
dumpObjectInfo ()
dumpObjectTree ()
dynamicPropertyNames () const : QList<QByteArray>
editStrategy () const : EditStrategy
endInsertColumns ()
endInsertRows ()
endMoveColumns ()
endMoveRows ()
endRemoveColumns ()
endRemoveRows ()
endResetModel ()
event ( QEvent * ) : bool
eventFilter ( QObject *, QEvent * ) : bool
fetchMore ( const QModelIndex & )
fieldIndex ( const QString & ) const : int
filter () const : QString
findChild ( const QString & ) const : T
findChildren ( const QString & ) const : QList<T>
findChildren ( const QRegExp & ) const : QList<T>
flags ( const QModelIndex & ) const : Qt::ItemFlags
hasChildren ( const QModelIndex & ) const : bool
hasIndex ( int, int, const QModelIndex & ) const : bool
headerData ( int, Qt::Orientation, int ) const : QVariant
headerDataChanged ( Qt::Orientation, int, int )
index ( int, int, const QModelIndex & ) const : QModelIndex
indexInQuery ( const QModelIndex & ) const : QModelIndex
inherits ( const char * ) const : bool
insertColumn ( int, const QModelIndex & ) : bool
insertColumns ( int, int, const QModelIndex & ) : bool
insertRecord ( int, const QSqlRecord & ) : bool
insertRow ( int, const QModelIndex & ) : bool
insertRowIntoTable ( const QSqlRecord & ) : bool
insertRows ( int, int, const QModelIndex & ) : bool
installEventFilter ( QObject * )
isDirty ( const QModelIndex & ) const : bool
isWidgetType () const : bool
itemData ( const QModelIndex & ) const : QMap<int, QVariant>
killTimer ( int )
lastError () const : QSqlError
layoutAboutToBeChanged ()
layoutChanged ()
match ( const QModelIndex &, int, const QVariant &, int, Qt::MatchFlags ) const : QModelIndexList
metaObject () const : const QMetaObject *
mimeData ( const QModelIndexList & ) const : QMimeData *
mimeTypes () const : QStringList
modelAboutToBeReset ()
modelReset ()
moveToThread ( QThread * )
objectName () const : QString
orderByClause () const : QString
parent ( const QModelIndex & ) const : QModelIndex
persistentIndexList () const : QModelIndexList
primaryKey () const : QSqlIndex
primeInsert ( int, QSqlRecord & )
property ( const char * ) const : QVariant
query () const : QSqlQuery
queryChange ()
receivers ( const char * ) const : int
record ( int ) const : QSqlRecord
record () const : QSqlRecord
removeColumn ( int, const QModelIndex & ) : bool
removeColumns ( int, int, const QModelIndex & ) : bool
removeEventFilter ( QObject * )
removeRow ( int, const QModelIndex & ) : bool
removeRows ( int, int, const QModelIndex & ) : bool
reset ()
revert ()
revertAll ()
revertRow ( int )
roleNames () const : const QHash<int, QByteArray> &
rowCount ( const QModelIndex & ) const : int
rowsAboutToBeInserted ( const QModelIndex &, int, int )
rowsAboutToBeMoved ( const QModelIndex &, int, int, const QModelIndex &, int )
rowsAboutToBeRemoved ( const QModelIndex &, int, int )
rowsInserted ( const QModelIndex &, int, int )
rowsMoved ( const QModelIndex &, int, int, const QModelIndex &, int )
rowsRemoved ( const QModelIndex &, int, int )
select () : bool
selectStatement () const : QString
sender () const : QObject *
setData ( const QModelIndex &, const QVariant &, int ) : bool
setEditStrategy ( EditStrategy )
setFilter ( const QString & )
setHeaderData ( int, Qt::Orientation, const QVariant &, int ) : bool
setItemData ( const QModelIndex &, const QMap<int, QVariant> & ) : bool
setLastError ( const QSqlError & )
setObjectName ( const QString & )
setParent ( QObject * )
setPrimaryKey ( const QSqlIndex & )
setProperty ( const char *, const QVariant & ) : bool
setQuery ( const QSqlQuery & )
setQuery ( const QString &, const QSqlDatabase & )
setRecord ( int, const QSqlRecord & ) : bool
setRoleNames ( const QHash<int, QByteArray> & )
setSort ( int, Qt::SortOrder )
setSupportedDragActions ( Qt::DropActions )
setTable ( const QString & )
sibling ( int, int, const QModelIndex & ) const : QModelIndex
signalsBlocked () const : bool
sort ( int, Qt::SortOrder )
span ( const QModelIndex & ) const : QSize
startTimer ( int ) : int
staticMetaObject : const QMetaObject
staticQtMetaObject : const QMetaObject
submit () : bool
submitAll () : bool
supportedDragActions () const : Qt::DropActions
supportedDropActions () const : Qt::DropActions
tableName () const : QString
thread () const : QThread *
timerEvent ( QTimerEvent * )
tr ( const char *, const char *, int ) : QString
trUtf8 ( const char *, const char *, int ) : QString
updateRowInTable ( int, const QSqlRecord & ) : bool

接下来我们看看虚函数:
virtual void clear ()
virtual QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const
virtual Qt::ItemFlags flags ( const QModelIndex & index ) const
virtual QVariant headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const
virtual bool insertRows ( int row, int count, const QModelIndex & parent = QModelIndex() )
virtual bool removeColumns ( int column, int count, const QModelIndex & parent = QModelIndex() )
virtual bool removeRows ( int row, int count, const QModelIndex & parent = QModelIndex() )
virtual int rowCount ( const QModelIndex & parent = QModelIndex() ) const
virtual bool setData ( const QModelIndex & index, const QVariant & value, int role = Qt::EditRole )
virtual void sort ( int column, Qt::SortOrder order )

这些函数里,我们看到了setData,clear,flags,data这四个我们曾经使用过的函数。

3、我们接下来,继续研究,它与父类的不同。
我们下面就对其的几个常用功能进行介绍,分别是修改,插入,删除,查询,和排序。

先我们新建一个QWidget Gui工程,添加.h文件database.h。
将database.h内容更改为:
#ifndef DATABASE_H
#define DATABASE_H
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QObject>
static bool createConnection()
{
      QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
      db.setDatabaseName("database.db");
      if(!db.open()) return false;
      QSqlQuery query;
      query.exec(QObject::tr("create table student (id int primary key, name vchar)"));
      query.exec(QObject::tr("insert into student values (0,'刘明')"));
      query.exec(QObject::tr("insert into student values (1,'陈刚')"));
      query.exec(QObject::tr("insert into student values (2,'王红')"));
      return true;
}

#endif // DATABASE_H

为了在数据库中能使用中文,我们使用了QObject类的tr()函数。而在下面的main()函数中我们也需要添加相应的代码来支持中文。

接着修改main函数
添加头文件
#include "database.h"
#include <QTextCodec>
加入两行代码
      QTextCodec::setCodecForTr(QTextCodec::codecForLocale());
      if(!createConnection()) return 1;
//一行支持中文显示,另一行连接数据库。

下面我们打开widget.ui,设计界面:
其部件包括若干按钮和Table View 、 Line Edit。

在widget.h中加入头文件:
#include <QSqlTableModel>
在private中声明全局对象:QSqlTableModel *model;

在widget.cpp文件中的构造函数里添加如下代码:
model = new QSqlTableModel(this);
model->setTable("student");
model->setEditStrategy(QSqlTableModel::OnManualSubmit);// 要提交修改才能使其生效
model->select(); //选取整个表的所有行
// model->removeColumn(1); //不显示name属性列,如果这时添加记录,则该属性的值添加不上
ui->tableView->setModel(model);
// ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);    //使其不可编辑

运行程序,可以看到,这个模型已经完全脱离了SQL语句,我们只需要执行select()函数就能查询整张表。上面有两行代码被注释掉了,你可以取消注释,测试一下它们的作用。

然后我们依次添加,按钮单击事件槽函数,最终代码如下:
void Widget::on_pushButton_clicked()//提交修改
{
      model->database().transaction(); //开始事务操作
      if (model->submitAll()) {
              model->database().commit(); //提交
        } else {
      model->database().rollback(); //回滚
      QMessageBox::warning(this, tr("tableModel"),
                                                  tr("数据库错误: %1")
                                                  .arg(model->lastError().text()));
            }

}

void Widget::on_pushButton_2_clicked()//撤销修改
{
      model->revertAll();
}

void Widget::on_pushButton_5_clicked()//查询
{
      QString name = ui->lineEdit->text();
      model->setFilter(QObject::tr("name = '%1'").arg(name)); //根据姓名进行筛选
      model->select(); //显示结果
}

void Widget::on_pushButton_6_clicked()//返回全表
{
      model->setTable("student");    //重新关联表
      model->select();    //这样才能再次显示整个表的内容

}

void Widget::on_pushButton_7_clicked()//升序排列
{
      model->setSort(0,Qt::AscendingOrder); //id属性,即第0列,升序排列
      model->select();

}

void Widget::on_pushButton_8_clicked()//降序排列
{
      model->setSort(0,Qt::DescendingOrder);
      model->select();

}

void Widget::on_pushButton_4_clicked()//删除当前行
{
      int curRow = ui->tableView->currentIndex().row();
            //获取选中的行
            model->removeRow(curRow);
            //删除该行
            int ok = QMessageBox::warning(this,tr("删除当前行!"),tr("你确定"
                                                                                               "删除当前行吗?"),
                                            QMessageBox::Yes,QMessageBox::No);
            if(ok == QMessageBox::No)
            {
                 model->revertAll(); //如果不删除,则撤销
            }
            else model->submitAll(); //否则提交,在数据库中删除该行

}

void Widget::on_pushButton_3_clicked()
{
      int rowNum = model->rowCount(); //获得表的行数
           int id = 10;
            model->insertRow(rowNum); //添加一行
            model->setData(model->index(rowNum,0),id);
            //model->submitAll(); //可以直接提交

}

这里就不在赘述,详见教程!
可以看到这个模型很强大,而且完全脱离了SQL语句,就算你不怎么懂数据库,也可以利用它进行大部分常用的操作。我们也看到了,这个模型提供了缓冲区,可以先将修改保存起来,当我们执行提交函数时,再去真正地修改数据库。当然,这个模型比前面的模型更高级,前面讲的所有操作,在这里都能执行。

五、QSqlRelationalTableModel 类(继承于QSqlTableModel)
1、前面我们已经看到了,QSqlTableModel类的强大,现在我们再来接触它的子类QSqlRelationalTableModel 类。
这个子类添加了外键(或者叫外码)的支持。
2、QSqlRelationalTableModel ,该类为单张的数据库表提供了一个可编辑的数据模型,它支持外键。
3、我们用一个简单的例子来看看吧!

新建一个QWidget Gui工程,添加.h文件:database.h。
更改内容后为:
#ifndef DATABASE_H
#define DATABASE_H
#include <QSqlDatabase>
#include <QSqlQuery>
static bool createConnection()
{
      QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
      db.setDatabaseName("database.db");
      if(!db.open()) return false;
      QSqlQuery query;
      query.exec("create table student (id int primary key, name vchar,course int)");
      query.exec("insert into student values (1,'yafei0',1)");
      query.exec("insert into student values (2,'yafei1',1)");
      query.exec("insert into student values (3,'yafei2',2)");

      query.exec("create table course (id int primary key, name vchar, teacher vchar)");
      query.exec("insert into course values (1,'Math','yafeilinux1')");
      query.exec("insert into course values (2,'English','yafeilinux2')");
      query.exec("insert into course values (3,'Computer','yafeilinux3')");
      return true;
}

#endif // DATABASE_H
我们在这里建立了两个表,student表中有一项是course,它是int型的,而course表的主键也是int型的。如果要将course项和course表进行关联,它们的类型就必须相同,一定要注意这一点。


接着修改main函数,添加头文件
#include "database.h"
添加一句代码:
if(!createConnection()) return 1;

接着修改widget.h文件:
添加头文件:#include <QSqlRelationalTableModel >
添加私有成员变量:QSqlRelationalTableModel  *model;

然后在widget.ui中添加一个Table View部件到窗体上。

最后修改widget.cpp中的构造函数,更改为:
i->setupUi(this);
      model = new QSqlRelationalTableModel (this);
            model->setEditStrategy(QSqlTableModel::OnFieldChange); //属性变化时写入数据库
            model->setTable("student");
            model->setRelation(2,QSqlRelation("course","id","name"));
            //将student表的第三个属性设为course表的id属性的外键,并将其显示为course表的name属性的值
            model->setHeaderData(0, Qt::Horizontal, QObject::tr("ID"));
            model->setHeaderData(1, Qt::Horizontal, QObject::tr("Name"));
            model->setHeaderData(2, Qt::Horizontal, QObject::tr("Course"));
            model->select();
            ui->tableView->setModel(model);

            ui->tableView->setItemDelegate(new QSqlRelationalDelegate(ui->tableView));//添加代理(委托)
//我们修改了model的提交策略,OnFieldChange表示只要属性被改动就马上写入数据库,这样就不需要我们再执行提交函数了。setRelation()函数实现了创建外键,注意它的格式就行了。

记得添加头文件:
#include <QSqlRelationalTableModel >
#include <QSqlTableModel>
#include <QSqlRelation>
#include <QSqlRelationalDelegate>
至此,大功告成了!走马观花耶》》》
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值