6.qsqlquerymodel源码分析

目录

  • 继承关系
  • 入口
    • 浅析qsqlquery
    • 刷新数据
  • 扩展列或者移除列以及取别名
  • 读取数据与增减行
    • 读取数据
  • 下一章节:如何使用qsqlquerymodel 与 qtableview实现自定义表格

继承关系

qsqlquerymodel 继承与qabstracttablemodel
在这里插入图片描述

入口

负责填充数据

void QSqlQueryModel::setQuery(const QString &query, const QSqlDatabase &db) //无法配置绑定参数
void QSqlQueryModel::setQuery(const QSqlQuery &query) //非常友好,支持自定义query

浅析qsqlquery

你会发现提供的构造qsqlquery中如果
携带sql字符串语句则 if (!query.isEmpty()) q->exec(query);自动执行,具体请看qInit()
所以在使用qsqlquery的过程中如果传入sql语句则不用手动执行
否则就需要自己执行exec

QSqlQuery::QSqlQuery(QSqlDatabase db)
{d = QSqlQueryPrivate::shared_null();qInit(this, QString(), db);
}
QSqlQuery::QSqlQuery(const QString& query, QSqlDatabase db)
{d = QSqlQueryPrivate::shared_null();qInit(this, query, db);
}
//1.提供的数据库连接无效则获取默认的数据库,且未开启static void qInit(QSqlQuery *q, const QString& query, QSqlDatabase db)
{QSqlDatabase database = db;if (!database.isValid())database = QSqlDatabase::database(QLatin1String(QSqlDatabase::defaultConnection), false);if (database.isValid()) {*q = QSqlQuery(database.driver()->createResult());}if (!query.isEmpty())q->exec(query);
}

数据返回
sqlResult 是由不同的数据库驱动提供的

QSqlRecord QSqlQuery::record() const
{QSqlRecord rec = d->sqlResult->record();if (isValid()) {for (int i = 0; i < rec.count(); ++i)rec.setValue(i, value(i));}return rec;
}QVariant QSqlQuery::value(int index) const
{if (isActive() && isValid() && (index > -1))return d->sqlResult->data(index);qWarning("QSqlQuery::value: not positioned on a valid record");return QVariant();
}

而为什么qsqlquery可以使用qsqlresult的protected东西,虽然不是相互继承关系
但因为在qsqlresult中声明了qsqlquery为友元类,所以依旧能够使用
但是外部是无法使用的
在这里插入图片描述
所以外部提供的 没什么太大的作用

const QSqlResult * result() const

实际

qsqlquery.record() 第一行是表头
所以执行next再获取才是数据库里面查询结果的第一行数据
setquery分析

所以我们了解了qsqlquery的处理机制,
我们就明白在执行qsqlquerymodel 的setquery
就是将已经存在数据的query填充到querymodel 模型中供外部使用

void QSqlQueryModel::setQuery(const QSqlQuery &query)
{Q_D(QSqlQueryModel);beginResetModel();QSqlRecord newRec = query.record();bool columnsChanged = (newRec != d->rec);//设置列数if (d->colOffsets.size() != newRec.count() || columnsChanged)d->initColOffsets(newRec.count());d->bottom = QModelIndex(); //最后一行与最后一列的坐标d->error = QSqlError();d->query = query;d->rec = newRec; //表头d->atEnd = true; //最后一行吗//获取数据的方式是由下往上则//这个模型不支持这样子的queryif (query.isForwardOnly()) {d->error = QSqlError(QLatin1String("Forward-only queries ""cannot be used in a data model"),QString(), QSqlError::ConnectionError);endResetModel();return;}if (!query.isActive()) {d->error = query.lastError();endResetModel();return;}//query是否存在数据if (query.driver()->hasFeature(QSqlDriver::QuerySize) && d->query.size() > 0) {d->bottom = createIndex(d->query.size() - 1, d->rec.count() - 1);} else {d->bottom = createIndex(-1, d->rec.count() - 1);d->atEnd = false;}// fetchMore does the rowsInserted stuff for incremental modelsfetchMore();  //endResetModel();queryChange();
}

不难看出初始化数据需要这样子的闭合关系

beginResetModel();
//-----填充数据域
endResetModel();

刷新数据

void QSqlQueryModel::fetchMore(const QModelIndex &parent)
{Q_D(QSqlQueryModel);if (parent.isValid())return;//预先刷新多少行,QSQL_PREFETCH=255d->prefetch(qMax(d->bottom.row(), 0) + QSQL_PREFETCH);
}

//limit>255
void QSqlQueryModelPrivate::prefetch(int limit)
{Q_Q(QSqlQueryModel);// 如果确实是最后一行则不往下执行if (atEnd || limit <= bottom.row() || bottom.column() == -1)return;QModelIndex newBottom;const int oldBottomRow = qMax(bottom.row(), 0);// try to seek directly// 查看数据是否超过limit行,则新行先预加载到这里,//一个预加载操作if (query.seek(limit)) {newBottom = q->createIndex(limit, bottom.column());} else {// have to seek back to our old position for MS Accessint i = oldBottomRow;if (query.seek(i)) {while (query.next())++i;newBottom = q->createIndex(i, bottom.column());} else {// empty or invalid querynewBottom = q->createIndex(-1, bottom.column());}atEnd = true; // this is the end.}if (newBottom.row() >= 0 && newBottom.row() > bottom.row()) {q->beginInsertRows(QModelIndex(), bottom.row() + 1, newBottom.row());bottom = newBottom; //更新最后一行坐标q->endInsertRows();} else {bottom = newBottom;}
}

可以看到执行插入操作

beginInsertRows();
//插入操作作用域
endInsertRows();

扩展列或者移除列以及取别名

不难发现就是往rect表头管理的record里面加入一个新的qsqlfield


//批量增加列
bool QSqlQueryModel::insertColumns(int column, int count, const QModelIndex &parent)
{Q_D(QSqlQueryModel);if (count <= 0 || parent.isValid() || column < 0 || column > d->rec.count())return false;beginInsertColumns(parent, column, column + count - 1);for (int c = 0; c < count; ++c) {QSqlField field;field.setReadOnly(true);field.setGenerated(false);d->rec.insert(column, field);if (d->colOffsets.size() < d->rec.count()) {int nVal = d->colOffsets.isEmpty() ? 0 : d->colOffsets[d->colOffsets.size() - 1];d->colOffsets.append(nVal);Q_ASSERT(d->colOffsets.size() >= d->rec.count());}for (int i = column + 1; i < d->colOffsets.count(); ++i)++d->colOffsets[i];}endInsertColumns();return true;
}//批量删除列
bool QSqlQueryModel::removeColumns(int column, int count, const QModelIndex &parent)
{Q_D(QSqlQueryModel);if (count <= 0 || parent.isValid() || column < 0 || column >= d->rec.count())return false;beginRemoveColumns(parent, column, column + count - 1);int i;for (i = 0; i < count; ++i)d->rec.remove(column);for (i = column; i < d->colOffsets.count(); ++i)d->colOffsets[i] -= count;endRemoveColumns();return true;
}
//取别名
bool QSqlQueryModel::setHeaderData(int section, Qt::Orientation orientation,const QVariant &value, int role)
{Q_D(QSqlQueryModel);if (orientation != Qt::Horizontal || section < 0 || columnCount() <= section)return false;if (d->headers.size() <= section)d->headers.resize(qMax(section + 1, 16));d->headers[section][role] = value;emit headerDataChanged(orientation, section, section);return true;
}// 获取表头列名
QVariant QSqlQueryModel::headerData(int section, Qt::Orientation orientation, int role) const
{Q_D(const QSqlQueryModel);if (orientation == Qt::Horizontal) {QVariant val = d->headers.value(section).value(role);if (role == Qt::DisplayRole && !val.isValid())val = d->headers.value(section).value(Qt::EditRole);if (val.isValid())return val;if (role == Qt::DisplayRole && d->rec.count() > section && d->columnInQuery(section) != -1)return d->rec.fieldName(section);}return QAbstractItemModel::headerData(section, orientation, role);
}

读取数据与增减行

因为是数据库查询的,我觉的没必要setData
我们只需要控制我们的列就行了
比如,我们可以在前面加一列—到时候传入个checkbox或者单选框
在加入一个选择管理器就可以做到选择功能
最后就是一列多个按键,我们也可以通过多增加列进行

    model->insertColumns(0,1);model->setHeaderData(0,Qt::Horizontal,QString("选择"));

动态列的字段数据

 0: QSqlField("", , tableName: "(not specified)", generated: no, autoValue: false, readOnly: true) "" 

读取数据


//返回行数据
QSqlRecord QSqlQueryModel::record(int row) const
{Q_D(const QSqlQueryModel);if (row < 0)return d->rec;QSqlRecord rec = d->rec;for (int i = 0; i < rec.count(); ++i)rec.setValue(i, data(createIndex(row, i), Qt::EditRole));return rec;
}//表头数据
QSqlRecord QSqlQueryModel::record() const
{Q_D(const QSqlQueryModel);return d->rec;
}QVariant QSqlQueryModel::data(const QModelIndex &item, int role) const
{Q_D(const QSqlQueryModel);if (!item.isValid())return QVariant();QVariant v;if (role & ~(Qt::DisplayRole | Qt::EditRole))return v;// 非原来的 则直接返回, 就是调用insertColumns加的则直接返回if (!d->rec.isGenerated(item.column()))return v;//获取在query中实际位置QModelIndex dItem = indexInQuery(item);if (dItem.row() > d->bottom.row())const_cast<QSqlQueryModelPrivate *>(d)->prefetch(dItem.row());if (!d->query.seek(dItem.row())) {d->error = d->query.lastError();return v;}return d->query.value(dItem.column());
}QModelIndex QSqlQueryModel::indexInQuery(const QModelIndex &item) const
{Q_D(const QSqlQueryModel);int modelColumn = d->columnInQuery(item.column());if (modelColumn < 0)return QModelIndex();return createIndex(item.row(), modelColumn, item.internalPointer());
}int QSqlQueryModelPrivate::columnInQuery(int modelColumn) const
{if (modelColumn < 0 || modelColumn >= rec.count() || !rec.isGenerated(modelColumn) || modelColumn >= colOffsets.size())return -1;return modelColumn - colOffsets[modelColumn];
}// 提供给委托使用的, 如果设置
QHash<int, QByteArray> QSqlQueryModel::roleNames() const
{return QHash<int, QByteArray> {{ Qt::DisplayRole, QByteArrayLiteral("display") }};
}

而rolename有什么用?
主要用于在qml中可以使用属性名如model.name , model.display之类的

    void initializeConstructor(QQmlAdaptorModelEngineData *const data){QV4::ExecutionEngine *v4 = data->v4;QV4::Scope scope(v4);QV4::ScopedObject proto(scope, v4->newObject());proto->defineAccessorProperty(QStringLiteral("index"), get_index, nullptr);proto->defineAccessorProperty(QStringLiteral("hasModelChildren"), get_hasModelChildren, nullptr);QV4::ScopedProperty p(scope);typedef QHash<QByteArray, int>::const_iterator iterator;for (iterator it = roleNames.constBegin(), end = roleNames.constEnd(); it != end; ++it) {const int propertyId = propertyRoles.indexOf(it.value());const QByteArray &propertyName = it.key();QV4::ScopedString name(scope, v4->newString(QString::fromUtf8(propertyName)));QV4::ExecutionContext *global = v4->rootContext();QV4::ScopedFunctionObject g(scope, v4->memoryManager->allocate<QV4::IndexedBuiltinFunction>(global, propertyId, QQmlDMCachedModelData::get_property));QV4::ScopedFunctionObject s(scope, v4->memoryManager->allocate<QV4::IndexedBuiltinFunction>(global, propertyId, QQmlDMCachedModelData::set_property));p->setGetter(g);p->setSetter(s);proto->insertMember(name, p, QV4::Attr_Accessor|QV4::Attr_NotEnumerable|QV4::Attr_NotConfigurable);}prototype.set(v4, proto);}

下一章节:如何使用qsqlquerymodel 与 qtableview实现自定义表格

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/466667.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue3中使用LogicFlow实现简单流程图

实现结果 实现功能&#xff1a; 拖拽创建节点自定义节点/边自定义快捷键人员选择弹窗右侧动态配置组件配置项获取/回显必填项验证历史记录&#xff08;撤销/恢复&#xff09; 自定义节点与拖拽创建节点 拖拽节点面板node-panel.vue <template><div class"node-…

Devops业务价值流:软件研发最佳实践

在当今快速迭代的软件开发环境中&#xff0c;DevOps业务价值流已成为推动软件研发高效与质量并重的关键实践。软件研发阶段作为产品生命周期的核心环节&#xff0c;其每一步都承载着将创意转化为现实的重要使命。在历经需求澄清的精准定位、架构设计的宏观规划以及项目初始化的…

wireshark工具使用

复制数据 1.右键展开整帧数据 2.复制“所有可见项目” mark标记数据 标记&#xff1a; 跳转&#xff1a; 保存成文件&#xff1a; 文件–>导出特定分组—>Marked packets only

管理 Elasticsearch 变得更容易了,非常容易!

作者&#xff1a;来自 Elastic Ken Exner Elasticsearch 用户&#xff0c;我们听到了你的心声。管理 Elasticsearch 有时会变得很复杂&#xff0c;面临的挑战包括性能调整、问题检测和资源优化。我们一直致力于简化你的体验。今天&#xff0c;我们宣布了自收购 Opster 以来的一…

深度洞察| 超6亿银发精准流量,40+泛银发群体参与消费三大变化

作者 | NewAgingPro团队 前言 9月24日&#xff0c;AgeClub成立银发流量及场景联盟&#xff08;简称&#xff1a;AgeMCN&#xff09;&#xff0c;助力银发经济高质量发展。 10月11日&#xff0c;AgeClub发布《2024银发流量全景洞察报告》&#xff0c;探索银发流量发展新模式…

Spring Boot——日志介绍和配置

1. 日志的介绍 在前面的学习中&#xff0c;控制台上打印出来的一大堆内容就是日志&#xff0c;可以帮助我们发现问题&#xff0c;分析问题&#xff0c;定位问题&#xff0c;除此之外&#xff0c;日志还可以进行系统的监控&#xff0c;数据采集等 2. 日志的使用 在程序中获取日…

Redis 组网方式入门

文章目录 一、组网方式1. 单实例模式描述优点缺点适用场景 2. 主从复制模式&#xff08;Master-Slave Replication&#xff09;描述优点缺点适用场景基于docker的redis主从复制1. 配置主节点2. 配置从节点3. 查看节点状态4. 验证主从数据同步5. 查看同步进度 3. 哨兵模式&#…

信号-2-信号捕捉

相关概念&#xff1a;递达 未决 / 阻塞 忽略 阻塞 vs 忽略 阻塞&#xff1a; 如果指定信号信号被阻塞&#xff0c; block期间该信号不能被递达&#xff0c;一直在pending表中。知道block被撤销后&#xff0c; 该信号才能递达&#xff0c;递达后对应pending位置置零。 忽…

(蓝桥杯C/C++)——基础算法(下)

目录 一、时空复杂度 1.时间复杂度 2.空间复杂度 3.分析技巧 4.代码示例 二、递归 1.递归的介绍 2.递归如何实现 3.递归和循环的比较 4.代码示例 三、差分 1.差分的原理和特点 2.差分的实现 3.例题讲解 四、枚举 1.枚举算法介绍 2.解空间的类型 3. 循环枚举解…

【极限编程(XP)】

极限编程&#xff08;XP&#xff09;简介 定义与核心价值观&#xff1a;极限编程&#xff08;Extreme Programming&#xff0c;XP&#xff09;是一种轻量级、敏捷的软件开发方法。它强调团队合作、客户参与、持续测试和快速反馈等价值观&#xff0c;旨在提高软件开发的效率和质…

如何编写安全的 Go 代码

原文&#xff1a;Jakub Jarosz - 2024.11.02 在编写 Go 代码时&#xff0c;如何时刻考虑安全性&#xff1f;要在一篇简短的文章中回答这个问题似乎不太可能。因此&#xff0c;我们将把范围缩小到一些具体做法上。 这些实践如果持续应用&#xff0c;将有助于我们编写健壮、安全…

Go八股(Ⅳ)***slice,string,defer***

***slice&#xff0c;string&#xff0c;defer*** 1.slice和arry的区别 arry&#xff1a; Go语言中arry即为数据的一种集合&#xff0c;需要在声明时指定容量和初值&#xff0c;且一旦声明就长度固定&#xff0c;访问时按照索引访问。通过内置函数len可以获取数组中的元素个…

使用 Mac 数据恢复从 iPhoto 图库中恢复照片

我们每个人都会遇到这种情况&#xff1a;在意识到我们不想丢失照片之前&#xff0c;我们会永久删除 iPhoto 图库中的一些照片。永久删除这些照片后&#xff0c;是否可以从 iPhoto 图库中恢复照片&#xff1f;本文将指导您使用免费的 Mac 数据恢复软件从 iPhoto 中恢复照片。 i…

Spark 的介绍与搭建:从理论到实践

目录 一、分布式的思想 &#xff08;一&#xff09;存储 &#xff08;二&#xff09;计算 二、Spark 简介 &#xff08;一&#xff09;发展历程 &#xff08;二&#xff09;Spark 能做什么&#xff1f; &#xff08;三&#xff09;spark 的组成部分 &#xff08;四&…

Spring Boot2(Spring Boot 的Web开发 springMVC 请求处理 参数绑定 常用注解 数据传递 文件上传)

SpringBoot的web开发 静态资源映射规则 总结&#xff1a;只要静态资源放在类路径下&#xff1a; called /static (or /public or /resources or //METAINF/resources 一启动服务器就能访问到静态资源文件 springboot只需要将图片放在 static 下 就可以被访问到了 总结&…

Vue2中使用firefox的pdfjs进行文件文件流预览

文章目录 1.使用场景2. 使用方式1. npm 包下载,[点击查看](https://www.npmjs.com/package/pdfjs-dist)2. 官网下载1. 放到public文件夹下面2. 官网下载地址[点我,进入官网](https://github.com/mozilla/pdf.js/tags?afterv3.3.122) 3. 代码演示4. 图片预览5. 如果遇到跨域或者…

2024软件测试面试热点问题

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 大厂面试热点问题 1、测试人员需要何时参加需求分析&#xff1f; 如果条件循序 原则上来说 是越早介入需求分析越好 因为测试人员对需求理解越深刻 对测试工…

C语言 | Leetcode C语言题解之第542题01矩阵

题目&#xff1a; 题解&#xff1a; /*** Return an array of arrays of size *returnSize.* The sizes of the arrays are returned as *returnColumnSizes array.* Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().*/ type…

C++总结

目录 一、面向对象的三大特性 二、引用 2.1 概念 2.2特性 三、类与对象 3.1概念 3.2 类的内容 3.3对象的创建 四、构造函数与析构函数 五、封装 六、继承 6.1概念与基础使用 6.2 继承权限 6.2.1 权限修饰符 6.2.2 继承权限 6.3构造函数 6.3.1 派生类与基类的构造函数关系 6.3.2…

2024 CSS保姆级教程二 - BFC详解

前言 - CSS中的文档流 在介绍BFC之前&#xff0c;需要先给大家介绍一下文档流。​ 我们常说的文档流其实分为定位流、浮动流、普通流三种。​ ​ 1. 绝对定位(Absolute positioning)​ 如果元素的属性 position 为 absolute 或 fixed&#xff0c;它就是一个绝对定位元素。​ 在…