QT开发(四十九)——数据库用户接口层

QT开发(四十九)——数据库用户接口层

用户接口层主要包括Qt SQL模块中的QSqlQueryModel、QSqlTableModel、QSqlRelationalTableModel。用户接口层的类实现了将数据库中的数据链接到窗口部件上,是使用模型/视图框架实现的,是更高层次的抽象,即便不熟悉SQL也可以操作数据库。需要注意的是,在使用用户接口层的类之前必须先实例化QCoreApplication对象。

QT中使用了自己的机制来避免使用SQL语句,提供了更简单的数据库操作及数据显示模型,分别是只读的QSqlQueryModel、操作单表的QSqlTableModel和支持外键的QSqlRelationalTableModel。

一、QSqlQueryModel

1、QSqlQueryModel简介

QSqlQueryModel类为SQL结果集提供了只读的数据模型,是执行SQL语句和遍历结果集的高级接口。QSqlQueryModel基于下层的QSqlQuery构建,用于提供数据给QTableView等视图类。

QSqlQueryModel模型默认是只读的,通过QSqlQueryModel派生自定义类重写setData()和flags()函数可以实现读写,或是使用QSqlTableModel。

2、QSqlQueryModel成员函数

QSqlQueryModel::QSqlQueryModel(QObject *parent = Q_NULLPTR)

使用给定的parent构建一个QSqlQueryModel空对象

[virtual] void QSqlQueryModel::clear()

清除模型并释放申请的任何资源

void QSqlQueryModel::setQuery(const QSqlQuery &query)

重置模型并设置数据源为给定的query。Query必须处于活跃状态

void QSqlQueryModel::setQuery(const QString &query, const QSqlDatabase &db = QSqlDatabase())

void QSqlQueryModel::setQuery(const QSqlQuery &query)

在给定的数据库连接db中执行查询query,如果数据库连接未指定或非法,使用默认的数据库连接

[protected] void QSqlQueryModel::setLastError(const QSqlError &error)

设置数据库发生的最后一个错误到error

[virtual] QVariant QSqlQueryModel::data(const QModelIndex &item, int role = Qt::DisplayRole) const

返回item数据项的role的值

3、QSqlQueryModel实例

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();

4、创建自定义QSqlQueryModel

QSqlQueryModel默认是只读的,在窗口上并不能对表格中的内容进行修改。如果要按照自己的需要显示数据和修改数据,可以创建自己的模型。要想使其可读写,需要自己的类继承自QSqlQueryModel,并且重写setData()和flags()两个函数。如果要改变数据的显示,就要重写data() 函数。

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;

SqlQueryModel.h文件:

#define SQLQUERYMODEL_H
 
#include <QSqlQueryModel>
#include <QObject>
#include <QModelIndex>
#include <QVariant>
#include <QString>
#include <QColor>
 
class SqlQueryModel : public QSqlQueryModel
{
    Q_OBJECT
public:
    SqlQueryModel(QObject *parent = 0);
 
protected:
    Qt::ItemFlags flags(const QModelIndex &index) const;
    bool setData(const QModelIndex &index, const QVariant &value, int role);
    QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const;
private:
    bool setName(int studentId, const QString &name);
    void refresh();
};
 
#endif // SQLQUERYMODEL_H

SqlQueryModel.cpp文件:

#

include "SqlQueryModel.h"
#include <QSqlQuery>
 
 
SqlQueryModel::SqlQueryModel(QObject *parent):QSqlQueryModel(parent)
{
}
 
Qt::ItemFlags SqlQueryModel::flags(const QModelIndex &index) const
{
    Qt::ItemFlags flags = QSqlQueryModel::flags(index);
    if (index.column() == 1) //第二个属性可更改
        flags |= Qt::ItemIsEditable;
    return flags;
}
 
bool SqlQueryModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    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;
}
 
QVariant SqlQueryModel::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;
}
 
bool SqlQueryModel::setName(int studentId, const QString &name)
{
    QSqlQuery query;
    query.prepare("update student set name = ? where id = ?");
    query.addBindValue(name);
    query.addBindValue(studentId);
    return query.exec();
}
 
void SqlQueryModel::refresh()
{
    setQuery("select * from student");
    setHeaderData(0, Qt::Horizontal, QObject::tr("id"));
    setHeaderData(1, Qt::Horizontal, QObject::tr("name"));
}

Main.cpp文件:

#include "SqlQueryModel.h"
#include <QApplication>
#include <QTableView>
#include <QSqlQueryModel>
#include <QSqlDatabase>
#include <QSqlQuery>
 
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
    db.setDatabaseName(":memory:");
    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,‘scorpio‘)");
    query.exec("insert into student values (1,‘alex‘)");
    query.exec("insert into student values (2,‘alexander‘)");
 
    QSqlQueryModel *model = new QSqlQueryModel;
    model->setQuery("select * from student");
    model->setHeaderData(0, Qt::Horizontal, QObject::tr("id"));
    model->setHeaderData(1, Qt::Horizontal, QObject::tr("name"));
    QTableView *view = new QTableView;
    view->setModel(model);
    view->setWindowTitle("QSqlQueryModel");
    view->show();
 
    SqlQueryModel *mymodel = new SqlQueryModel;
    mymodel->setQuery("select * from student");
    mymodel->setHeaderData(0, Qt::Horizontal, QObject::tr("id"));
    mymodel->setHeaderData(1, Qt::Horizontal, QObject::tr("name"));
    QTableView *view1 = new QTableView;
    view1->setWindowTitle("SqlQueryModel"); //修改窗口标题
    view1->setModel(mymodel);
    view1->show();
    return a.exec();
}

二、QSqlTableModel

1、QSqlTableModel简介

QSqlTableModel提供了一个一次只能操作单个SQL表的读写模型,它是QSqlQuery的更高层次的替代品,可以浏览和修改独立的SQL表,并且只需编写很少的代码,而且不需要了解SQL语法。

QSqlTableModel类为单个数据库表提供了可编辑的数据模型,是从单个表中读写数据库记录的高级接口。QSqlTableModel基于下层的QSqlQuery构建,用于提供数据给QTableView等视图类。

2、QSqlTableModel成员函数

QSqlTableModel::QSqlTableModel(QObject *parent = Q_NULLPTR, QSqlDatabase db = QSqlDatabase())

构建一个QSqlTableModel空对象,设置父对象为parent,数据库连接为db,如果db非法,使用默认数据库连接。

[signal] void QSqlTableModel::beforeDelete(int row)

[signal] void QSqlTableModel::beforeInsert(QSqlRecord &record)

[signal] void QSqlTableModel::beforeUpdate(int row, QSqlRecord &record)

QSqlDatabase QSqlTableModel::database() const

返回模型的数据库连接

[virtual protected] bool QSqlTableModel::deleteRowFromTable(int row)

从当前活跃的数据库表中删除给定的行

EditStrategy QSqlTableModel::editStrategy() const

返回当前的编辑策略

int QSqlTableModel::fieldIndex(const QString &fieldName) const

返回字段名为fieldName的字段的索引,如果没有相应字段返回-1

QString QSqlTableModel::filter() const

返回当前设置的过滤器

bool QSqlTableModel::insertRecord(int row, const QSqlRecord &record)

在row行插入一条记录record,如果row为负数,追加到尾部

bool QSqlTableModel::isDirty(const QModelIndex &index) const

如果index位置的值是脏值,返回true。脏值是被模型修改单尚未写入数据库的值

bool QSqlTableModel::isDirty() const

如果模型包含被修改的值并且没有提交到数据库,返回true

QSqlIndex QSqlTableModel::primaryKey() const

返回当前表的主键

3、QSqlTableModel使用

#include <QApplication>
#include <QSqlTableModel>
#include <QTableView>
#include <QSqlDatabase>
#include <QSqlQuery>
 
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
    db.setDatabaseName(":memory:");
    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,‘scorpio‘)");
    query.exec("insert into student values (1,‘alex‘)");
    query.exec("insert into student values (2,‘alexander‘)");
 
    QSqlTableModel *model = new QSqlTableModel;
    model->setTable("student");
    model->setEditStrategy(QSqlTableModel::OnManualSubmit);
    model->select(); //选取整个表的所有行
 
    QTableView *view = new QTableView;
    view->setModel(model);
    view->show();
 
    return a.exec();
}

A、修改操作

提交修改

//开始事务操作
model->database().transaction();
if (model->submitAll())
{
    model->database().commit(); //提交
}
else
{
    model->database().rollback(); //回滚
    QMessageBox::warning(this, tr("tableModel"),
                 tr("数据库错误: %1").arg(model->lastError().text()));
}

撤销修改

model->revertAll();

B、查询操作

QString name = lineedit->text();

//根据姓名进行筛选

model->setFilter(QString("name = ‘%1‘").arg(name));

//显示结果

model->select();

model->setTable("student"); //重新关联表

model->select();//选择整个表格

C、排序操作

升序:

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

model->select();

降序:

model->setSort(0, Qt::DescendingOrder);

model->select();

D、删除操作

//获取选中的行

int curRow = view->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(); //否则提交,在数据库中删除该行

E、插入操作

int rowNum = model->rowCount(); //获得表的行数

int id = 10;

model->insertRow(rowNum); //添加一行

model->setData(model->index(rowNum,0),id);

三、QSqlRelationalTableModel

1、QSqlRelationalTableModel简介

QSqlRelationalTableModel为了单个数据库表格提供了可编辑的数据模型。

QSqlRelationalTableModel继承自QSqlTableModel,并对其进行了扩展,提供了对外键的支持。外键就是一个表中的一个属性和其他表中的主键属性之间的一对一的映射。

2、QSqlRelationalTableModel成员函数

[virtual] void QSqlRelationalTableModel::setRelation(int column, const QSqlRelation &relation)

当前表中第column列为QSqlRelation(tableName,indexColumn,displayColumn)的外键

QVariant QSqlRelationalTableModel::data(const QModelIndex &index, int role = Qt::DisplayRole) const

返回index的数据

[virtual protected] bool QSqlRelationalTableModel::insertRowIntoTable(const QSqlRecord &values)

向表中插入一条记录values

QSqlRelation QSqlRelationalTableModel::relation(int column) const

返回表格中第column列的关系

[virtual] QSqlTableModel *QSqlRelationalTableModel::relationModel(int column) const

返回外键column要访问的表的QSqlTableModel对象

[virtual] bool QSqlRelationalTableModel::setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole)

设置index数据项的值为value,数据项角色为role

[virtual] void QSqlRelationalTableModel::setTable(const QString &table)

设置模型的表格为table

3、使用外键

#include<QSqlRelationalTableModel>
#include <QApplication>
#include <QTableView>
#include <QSqlDatabase>
#include <QSqlQuery>
 
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
    db.setDatabaseName(":memory:");
    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,‘scorpio‘,1)");
    query.exec("insert into student values(2,‘alex‘,1)");
    query.exec("insert into student values(3,‘alexandar‘,3)");
 
    query.exec("create table course (id int primarykey, name vchar, teacher vchar)");
    query.exec("insert into course values(1,‘Math‘,‘kim‘)");
    query.exec("insert into course values(2,‘English‘,‘kim‘)");
    query.exec("insert into course values(3,‘Computer‘,‘kim‘)");
 
    QSqlRelationalTableModel *model = new QSqlRelationalTableModel;
    //属性变化时写入数据库
    model->setEditStrategy(QSqlTableModel::OnFieldChange);
    model->setTable("student");
    //将student表的第2个属性设为course表的id属性的外键,
    //并将其显示为course表的name属性的值
    model->setRelation(2,QSqlRelation("course","id","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();
    QTableView *view = new QTableView;
    view->setModel(model);
    view->show();
 
    return a.exec();
}

4、使用委托

为了控制表中某些数据项的数据的可选类型或是数据内容,可以使用委托。QT提供了QSqlRelationalDelegate委托类,可以为QSqlRelationalTableModel显示和编辑数据。不同于默认的委托,QSqlRelationalDelegate为外键提供了字段的下拉框。

view->setItemDelegate(new QSqlRelationalDelegate(view));

时间: 2024-12-26 18:37:16

QT开发(四十九)——数据库用户接口层的相关文章

QT开发(十九)——QT内存泄漏问题

QT开发(十九)--QT内存泄漏问题 一.QT对象间的父子关系 QT最基础和核心的类是:QObject,QObject内部有一个list,会保存children,还有一个指针保存parent,当自己析构时,会自己从parent列表中删除并且析构所有的children. QT对象之间可以存在父子关系,每一个对象都可以保存它所有子对象的指针,每一个对象都有一个指向其父对象的指针. 当指定QT对象的父对象时,父对象会在子对象链表中加入该对象的指针,该对象会保存指向其父对象的指针. 当QT对象被销毁时,

QT开发(四十八)——数据库SQL接口层

QT开发(四十八)--数据库SQL接口层 SQL接口层提供了对数据库的访问,主要类包括Qt SQL模块中的QSqlDatabase.QSqlQuery.QSqlError.QSqlField.QSqlIndex和QSqlRecord.QSqlDatabase类用于创建数据库连接,QSqlQuery用于使用SQL语句实现与数据库交互. 一.QSqlDatabase 1.QSqlDatabase简介 QSqlDatabase类提供了通过连接访问数据库的接口,QSqlDatabase对象本身代表一个连

QT开发(十四)——QT绘图系统

QT开发(十四)--QT绘图系统 一.QT绘图原理 Qt4中的2D绘图系统称为Arthur绘图系统,可以使用相同的API在屏幕上和绘图设备上进行绘制,主要基于QPainter.QPainterDevice和 QPainterEngine.QPainter执行绘图操作,QPainterDevice提供绘图设备,是一个二维空间的抽象,QPainterEngine提供一些接口.QPainter用来执行具体的绘图相关操作,如画点,画线,填充,变换,alpha通道等.QPaintDevice类是能够进行绘

QT开发(十二)——QT事件处理机制

QT开发(十二)--QT事件处理机制 一.QT事件简介 QT程序是事件驱动的, 程序的每个动作都是由内部某个事件所触发.QT事件的发生和处理成为程序运行的主线,存在于程序整个生命周期. 常见的QT事件类型如下: 键盘事件: 按键按下和松开 鼠标事件: 鼠标移动,鼠标按键的按下和松开 拖放事件: 用鼠标进行拖放 滚轮事件: 鼠标滚轮滚动 绘屏事件: 重绘屏幕的某些部分 定时事件: 定时器到时 焦点事件: 键盘焦点移动 进入和离开事件: 鼠标移入widget之内,或是移出 移动事件: widget的

QT开发(十六)——QT绘图实例-钟表

QT开发(十六)--QT绘图实例-钟表 一.钟表实现原理 钟表的实现需要设置定时器,定时器每隔一秒发送timeout()信号到QWidget::update()槽函数,update()槽函数将会重绘一次窗口,重写重绘事件函数paintEvent(QPaintEvent *event),根据获取的当前系统时间的时钟.分钟.秒钟重绘钟表的时针.分针.秒针. QTimer *timer = new QTimer(this); timer->start(1000);//一秒钟 connect(timer

从零开始学ios开发(十九):Application Settings and User Defaults(上)

在iphone和ipad中,有一个东西大家一定很熟悉,那个东西就是Settings. 这次要学习的东西说白了很简单,就是学习如何在Settings中对一个app的某些属性进行设置,反过来,在app中更改了一些属性值,也会反应到Settings中,这个功能很常用,实现起来也相对简单,但是内容还是比较多的. 首先还是对Settings进行一个简单的说明,虽然我们经常打开Settings,但是很少对Settings进行过仔细的研究,不过作为一名ios的开发人员,有这个必要对Settings进行一番探索

“全栈2019”Java第八十九章:接口中能定义内部类吗?

难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第八十九章:接口中能定义内部类吗? 下一章 "全栈2019"Java第九十章:内部类可以向上或向下转型吗? 学习小组 加入同步学习小组,共同交流与进步. 方式一:关注头条号Gorhaf,私信"Java学习小组". 方式二:关注公众号Gorhaf,回复"Java学

Python进阶(四十九)-初识Flask Blueprint

Python进阶(四十九)-初识Flask Blueprint 前言   在进行Python Web开发时选择Flask框架.项目模块划分阶段,使用Blueprint(这里暂且称之为“蓝本”).Blueprint通过把实现不同功能的module分开,从而把一个大的application分割成各自实现不同功能的module.在一个Blueprint中可以调用另一个blueprint的view function, 但要加相应的blueprint名.   Blueprint还有其他好处,其本质上来说就

无限互联奖学金文章连载北京总部四十九期胡梦川 第一篇

无限互联奖学金文章连载北京总部四十九期胡梦川 第一篇: 今天是来到无限互联的第四天,严格来说已经第六天了,刚来就是开班典礼,给人一种很好的氛围.老师讲了很多关于以后学习的技巧和规定,我的第一感觉是,比备战高考还要严格,不过这才能体现一个组织的负责任.正式开讲才感觉到这个班级的大神无处不在,不努力根本赶不上,就是这个学习氛围和高强度的练习很重要.多用心你才能感觉到有些事其实很简单.关于学习时间大家基本都是一天不动的在敲代码,等于给自己一个机会吧.时间飞逝,抓住机会才重要.刚来第一周,感受最深就是好