当前位置: 首页 > news >正文

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实现自定义表格

相关文章:

6.qsqlquerymodel源码分析

目录 继承关系入口浅析qsqlquery刷新数据 扩展列或者移除列以及取别名读取数据与增减行读取数据 下一章节&#xff1a;如何使用qsqlquerymodel 与 qtableview实现自定义表格 继承关系 qsqlquerymodel 继承与qabstracttablemodel 入口 负责填充数据 void QSqlQueryModel::s…...

【人工智能】ChatGPT多模型感知态识别

目录 ChatGPT辅助细化知识增强&#xff01;一、研究背景二、模型结构和代码任务流程一&#xff1a;启发式生成 三、数据集介绍三、性能展示实现过程运行过程训练过程 ChatGPT辅助细化知识增强&#xff01; 多模态命名实体识别&#xff08;MNER&#xff09;最近引起了广泛关注。…...

2.ARM_ARM是什么

CPU工作原理 CPU与内存中的内容&#xff1a; 内存中存放了指令&#xff0c;每一个指令存放的地址不一样&#xff0c;所需的内存空间也不一样。 运算器能够进行算数运算和逻辑运算&#xff0c;这些运算在CPU中都是以运算电路的形式存在&#xff0c;一个运算功能对应一种运算电…...

深入学习指针(5)!!!!!!!!!!!!!!!

文章目录 1.回调函数是什么&#xff1f;2.qsort使用举例2.1使用qsort函数排序整形数据2.2使用sqort排序结构数据 3.qsort函数的模拟实现 1.回调函数是什么&#xff1f; 回调函数就是⼀个通过函数指针调⽤的函数。 如果你把函数的指针&#xff08;地址&#xff09;作为参数传递…...

离散无记忆信道

目录 离散无记忆信道输入概率输出概率联合分布概率信道逆向概率一些记号示例1示例2 离散无记忆信道 离散&#xff1a;输入输出字母表都是有限的 无记忆&#xff1a;输出字符 d i d_i di​ 被接收到的概率只依赖于当前的输入 c i c_i ci​, 而与前面的输入无关。 一个离散无记…...

【STM32】项目实战——OV7725/OV2604摄像头颜色识别检测(开源)

本篇文章分享关于如何使用STM32单片机对彩色摄像头&#xff08;OV7725/OV2604&#xff09;采集的图像数据进行分析处理&#xff0c;最后实现颜色的识别和检测。 目录 一、什么是颜色识别 1、图像采集识别的一些基本概念 1. 像素&#xff08;Pixel&#xff09; 2. 分辨率&am…...

《AI产品经理手册》——解锁AI时代的商业密钥

在当今这个日新月异的AI时代&#xff0c;每一位产品经理都面临着前所未有的挑战与机遇&#xff0c;唯有紧跟时代潮流&#xff0c;深入掌握AI技术的精髓&#xff0c;才能在激烈的市场竞争中独占鳌头。《AI产品经理手册》正是这样一部为AI产品经理量身定制的实战宝典&#xff0c;…...

ArcGIS 地理信息系统 任意文件读取漏洞复现

0x01 产品简介 ArcGIS是由美国Esri公司研发的地理信息系统(GIS)软件,它整合了数据库、软件工程、人工智能、网络技术、云计算等主流的IT技术,旨在为用户提供一套完整的、开放的企业级GIS解决方案,它包含了一套带有用户界面组件的Windows桌面应用。可以实现从简单到复杂的…...

11.07学习

一、三中代码解决鸡兔同笼问题 1.直接解方程 #include <stdio.h> int main() { int heads, feet, chickens, rabbits; printf("请输入总头数&#xff1a;"); scanf("%d", &heads); printf("请输入总脚数&#xff1a;"); scanf(…...

【JavaEE】常见锁策略、CAS

目录 常见的锁策略 乐观锁 vs 悲观锁 重量级锁 vs 轻量级锁 自锁锁和挂起等待锁 读写锁 可重入锁 vs 不可重入锁 公平锁 vs 非公平锁 CAS ABA问题 synchronized几个重要的机制 1、锁升级 2、锁消除 3、锁粗化 常见的锁策略 乐观锁 vs 悲观锁 乐观锁和悲观锁是锁的…...

Logstash 安装与部署(无坑版)

下载 版本对照关系&#xff1a;ElasticSearch 7.9.2 和 Logstash 7.9.2 &#xff1b; 官方下载地址 选择ElasticSearch版本一致的Logstash版本 https://www.elastic.co/cn/downloads/logstash 下载链接&#xff1a;https://artifacts.elastic.co/downloads/logstash/logst…...

鸿蒙开发:ArkUI Toggle 组件

ArkUI提供了一套完整的UI开发工具集&#xff0c;帮助开发者高效完成页面的开发。它融合了语言、编译器、图形构建等关键的应用UI开发底座&#xff0c;为应用的UI开发提供了完整的基础设施&#xff0c;包括简洁的UI语法、丰富的UI功能以及实时界面预览工具等&#xff0c;可以支持…...

使用Matlab神经网络工具箱

综述 在大数据和人工智能时代&#xff0c;神经网络是一种最为常见的数据分析和拟合工具。本报告以常用分析软件Matlab为例&#xff0c;介绍其中神经网络工具箱使用方法。 Step 1: 打开matlab 安装matlab 2018以上版本后&#xff0c;双击图标打开。 Step 2: 打开神经网络拟合…...

【面试题】Hive 查询:如何查找用户连续三天登录的记录

1. 需求概述 在分析用户行为时&#xff0c;查询用户的连续登录数据是一个常见需求。例如&#xff0c;我们需要找出每个用户连续三天登录的记录。给定一个包含用户登录记录的表&#xff0c;我们需要对这些数据进行处理&#xff0c;提取出用户连续三天登录的日期。 2. 问题说明…...

高活跃社区 Doge 与零知识证明的强强联手,QED 重塑可扩展性

在 Web3 的广阔生态中&#xff0c;Doge 无疑是最具标志性和趣味性的项目之一。作为一种起源于网络文化的符号&#xff0c;Doge 从最初的互联网玩笑发展为如今备受全球关注的去中心化资产&#xff0c;依靠其独特的魅力和广泛的用户基础&#xff0c;构建了一个充满活力的社区。 …...

qt QAbstractTableModel详解

1、概述 QAbstractTableModel 是 Qt 框架中的一个类&#xff0c;用于在 Qt 应用程序中实现自定义的表格数据模型。它是 Qt 中的一个抽象基类&#xff0c;提供了创建和操作表格数据所需的接口。QAbstractTableModel 为模型提供了一个标准接口&#xff0c;这些模型将其数据表示为…...

掌握 Navicat 数据库结构设计 | 提升工作效率的秘诀

近期&#xff0c;我们介绍了 Navicat 17 的一系列的新特性&#xff0c;包括&#xff1a;兼容更多数据库、全新的模型设计、可视化 BI、智能数据分析、可视化查询解释、高质量数据字典、增强用户体验、扩展 MongoDB 功能、轻松固定查询结果、便捷 URI、支持更多平台等。今天&…...

Ollama AI 框架缺陷可能导致 DoS、模型盗窃和中毒

近日&#xff0c;东方联盟网络安全研究人员披露了 Ollama 人工智能 (AI) 框架中的六个安全漏洞&#xff0c;恶意行为者可能会利用这些漏洞执行各种操作&#xff0c;包括拒绝服务、模型中毒和模型盗窃。 知名网络安全专家、东方联盟创始人郭盛华表示&#xff1a;“总的来说&…...

vue 3:监听器

目录 1. 基本概念 2. 侦听数据源类型 1. 监听getter函数 2. 监听 ref 或 reactive 的引用 3. 多个来源组成的数组 4. 避免直接传递值&#xff01;&#xff01;&#xff01; 3. 深层侦听器 4. 立即回调的侦听器 5. 一次性侦听器 6. watchEffect() 7. 暂停、恢复和停止…...

Java学习路线:Maven(四)Maven常用命令

在IDEA的Maven模块中&#xff0c;可以看到每个项目都有一个生命周期 这些生命周期实际上是Maven的一些插件&#xff0c;每个插件都有各自的功能&#xff0c;而双击这些插件就可以执行命令 这些命令的功能如下&#xff1a; clean&#xff1a;清除整个 target文件夹&#xff0c…...

RocketMQ延迟消息机制

两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数&#xff0c;对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后&#xf…...

IT供电系统绝缘监测及故障定位解决方案

随着新能源的快速发展&#xff0c;光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域&#xff0c;IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选&#xff0c;但在长期运行中&#xff0c;例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...

Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理

引言 Bitmap&#xff08;位图&#xff09;是Android应用内存占用的“头号杀手”。一张1080P&#xff08;1920x1080&#xff09;的图片以ARGB_8888格式加载时&#xff0c;内存占用高达8MB&#xff08;192010804字节&#xff09;。据统计&#xff0c;超过60%的应用OOM崩溃与Bitm…...

如何在最短时间内提升打ctf(web)的水平?

刚刚刷完2遍 bugku 的 web 题&#xff0c;前来答题。 每个人对刷题理解是不同&#xff0c;有的人是看了writeup就等于刷了&#xff0c;有的人是收藏了writeup就等于刷了&#xff0c;有的人是跟着writeup做了一遍就等于刷了&#xff0c;还有的人是独立思考做了一遍就等于刷了。…...

Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)

在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马&#xff08;服务器方面的&#xff09;的原理&#xff0c;连接&#xff0c;以及各种木马及连接工具的分享 文件木马&#xff1a;https://w…...

【JVM面试篇】高频八股汇总——类加载和类加载器

目录 1. 讲一下类加载过程&#xff1f; 2. Java创建对象的过程&#xff1f; 3. 对象的生命周期&#xff1f; 4. 类加载器有哪些&#xff1f; 5. 双亲委派模型的作用&#xff08;好处&#xff09;&#xff1f; 6. 讲一下类的加载和双亲委派原则&#xff1f; 7. 双亲委派模…...

深入浅出Diffusion模型:从原理到实践的全方位教程

I. 引言&#xff1a;生成式AI的黎明 – Diffusion模型是什么&#xff1f; 近年来&#xff0c;生成式人工智能&#xff08;Generative AI&#xff09;领域取得了爆炸性的进展&#xff0c;模型能够根据简单的文本提示创作出逼真的图像、连贯的文本&#xff0c;乃至更多令人惊叹的…...

6️⃣Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙

Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙 一、前言:离区块链还有多远? 区块链听起来可能遥不可及,似乎是只有密码学专家和资深工程师才能涉足的领域。但事实上,构建一个区块链的核心并不复杂,尤其当你已经掌握了一门系统编程语言,比如 Go。 要真正理解区…...

OCR MLLM Evaluation

为什么需要评测体系&#xff1f;——背景与矛盾 ​​ 能干的事&#xff1a;​​ 看清楚发票、身份证上的字&#xff08;准确率>90%&#xff09;&#xff0c;速度飞快&#xff08;眨眼间完成&#xff09;。​​干不了的事&#xff1a;​​ 碰到复杂表格&#xff08;合并单元…...

基于Uniapp的HarmonyOS 5.0体育应用开发攻略

一、技术架构设计 1.混合开发框架选型 &#xff08;1&#xff09;使用Uniapp 3.8版本支持ArkTS编译 &#xff08;2&#xff09;通过uni-harmony插件调用原生能力 &#xff08;3&#xff09;分层架构设计&#xff1a; graph TDA[UI层] -->|Vue语法| B(Uniapp框架)B --&g…...