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.xdnf.cn/news/6069.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

【JavaEE】认识线程

一、引入线程 在任务管理器界面可以看到很多进程&#xff0c;可以利用CPU多核心这一点来更有效的执行这些进程&#xff0c;即在处理过程中将CPU的多个时间片分配给每个进程&#xff0c;这样的 "多进程编程"就可以起到并发编程的效果&#xff0c;因为进程可以被调度到…

qt QStatusBar详解

1、概述 QStatusBar是Qt框架提供的一个小部件&#xff0c;用于在应用程序窗口底部显示状态信息。它可以显示一些固定的文本和图标&#xff0c;并且可以通过API动态更新显示内容。QStatusBar通常是一个水平的窗口部件&#xff0c;能够显示多行文本内容&#xff0c;非常适合用于…

【Ubuntu】ubuntu 22.04 设置 Xorg 弃用 Wayland

# 编辑gdm3配置文件 sudo vim /etc/gdm3/custom.conf # 重启gdm3 sudo systemctl restart gdm3方式一&#xff1a;如果进行上述操作后&#xff0c;有对比度严重错误问题&#xff0c;请执行下列命令 # 安装驱动 sudo ubuntu-drivers autoinstall 方式二&#xff1a;推荐尝试方式…

日语学习的难易程度

日语学习的难易程度是一个相对主观的问题&#xff0c;它受到多种因素的影响&#xff0c;包括个人的语言学习能力、学习方法、学习时间、学习资源的可获得性以及个人对日语文化的兴趣和投入程度等。以下是对日语学习难易程度的一些分析&#xff1a; 优点与易学之处 文字系统&am…

WPF 打包

打包为单个exe文件直接运行 - - -版本.NET8 新建WPF项目 右键 - 发布 选择发布文件夹 选择发布文件夹 选择发布文件夹 配置 配置,保存 发布 WPF 打包为exe安装程序 示例 实现思路 引导项目中嵌入其它项目可运行目录的zip引导项目中解压zip文件到指定文件夹是…

RTC精度及校准

RTC精度偏差&#xff1a; RTC的基准时间和精度与石英晶体的频率相关&#xff0c;晶体的谐振频率取决于温度&#xff0c;因此RTC性能与温度相关&#xff0c;晶体的频率偏差是晶体正常频率的温度反转函数。 一、硬件方面&#xff1a; 1.使用高精度振荡器的RTC模块&#xff1b; …

C++ Qt6 QtQuick/QML入门进阶与项目实战视频教程

课程介绍 C Qt这些年在PC客户端、嵌入式、汽车座舱仪表等领域应用很广泛&#xff0c;例如剪映专业版、微信4.0、亿图脑图、Steam、美图秀秀、腾讯会议、钉钉(部分模块)等都是使用C QWidget/QML开发。特别是QML这种声明式UI开发更加快捷&#xff0c;QML的界面开发效率相对于QWid…

Linux:防火墙和selinux对服务的影响

1-1selinux 1-1 SELinux是对程序、文件等权限设置依据的一个内核模块。由于启动网络服务的也是程序&#xff0c;因此刚好也 是能够控制网络服务能否访问系统资源的一道关卡。 1-2 SELinux是通过MAC的方式来控制管理进程&#xff0c;它控制的主体是进程&#xff0c;而目标则是…

逻辑回归处理非线性关系与支持向量机的性能对比

逻辑回归是一种常用的线性分类方法&#xff0c;通常用于处理线性关系的二分类任务。但是&#xff0c;对于非线性问题&#xff0c;传统的逻辑回归模型可能表现不佳&#xff0c;因为它假设数据可以被一个线性决策边界分割开来。为了使逻辑回归能够处理非线性关系&#xff0c;我们…

2021数二第9题 线代 一个方程组的解是另一个方程组的解

题目展示的是一个方程组的列向量 可由另一个列向量表示所以是矩阵的转置

C#与C++交互开发系列(二十):跨进程通信之共享内存(Shared Memory)

1、前言 共享内存&#xff08;Shared Memory&#xff09;是一种高效的跨进程通信方式&#xff0c;尤其适用于同一台计算机上的进程之间的高速数据传输。与套接字相比&#xff0c;共享内存允许多个进程直接访问同一块内存区域&#xff0c;减少了数据传输的中间步骤&#xff0c;…

防火墙|WAF|漏洞|网络安全

防火墙|WAF|漏洞|网络安全 防火墙 根据内容分析数据包&#xff1a; 1、源IP和目的IP地址 2、有效负载中的内容。 3、数据包协议&#xff08;例如&#xff0c;连接是否使用 TCP/IP 协议&#xff09;。 4、应用协议&#xff08;HTTP、Telnet、FTP、DNS、SSH 等&#xff09;。 5…

web——warmup——攻防世界

这道题还是没有做出来。。&#xff0c;来总结一下 1.ctrlU显示源码 2.看见body里有source.php 打开这个source.php 看见了源码 highlight_file(FILE); 这行代码用于高亮显示当前文件的源码&#xff0c;适合调试和学习&#xff0c;但在生产环境中通常不需要。 class emmm 定义…

HTML第一次作业

制作带有下拉悬停菜单的导航栏 <!DOCTYPE html> <html> <head><meta charset"utf-8"><title>带有下拉悬停菜单的导航栏</title><style>* {margin: 0;padding: 0;}#menu {background-color: blue;width: 100%;height: 50p…

数据结构 C/C++(实验三:队列)

&#xff08;大家好&#xff0c;今天分享的是数据结构的相关知识&#xff0c;大家可以在评论区进行互动答疑哦~加油&#xff01;&#x1f495;&#xff09; 目录 提要&#xff1a;实验题目 一、实验目的 二、实验内容及要求 三、算法思想 实验1 实验2 四、源程序及注释…

Chromium127编译指南 Mac篇(二)- 安装Xcode

1. 概述 在Chromium开发的道路上&#xff0c;为Mac平台搭建正确的环境是至关重要的第一步。本文将聚焦于Xcode的安装过程&#xff0c;它作为Mac上不可或缺的开发工具&#xff0c;为Chromium的编译提供了必要的编译器和工具链。 我们将详细解析如何选择、下载并安装适合Chromium…

移动应用开发 实验二:标准身高计算器

文章目录 准备工作一&#xff0c;创建Android Studio项目二&#xff0c;创建活动模块三&#xff0c;设计用户界面&#xff08;一&#xff09;设置页面布局&#xff08;二&#xff09;添加标题文本控件&#xff08;三&#xff09;设计体重输入框&#xff08;四&#xff09;设计性…

这个超级棒,我收藏的样机素材,统统分享给你们

Hello&#xff0c;大家好&#xff0c;我是后期圈&#xff01;工作不息摸鱼不止&#xff01;继续给圈友们带来有趣好玩的推荐&#xff0c;圈友们在摸鱼的同时别忘记多多点赞支持一波呀 今天给大家分享 4个超实用效率高质量网站&#xff0c;请各位偷偷收藏使用&#xff0c;懂得都…

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

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

spark-本地模式的配置和简单使用

python环境的安装 在虚拟机中&#xff0c;只能安装一个python的版本&#xff0c;若想要安装别的版本&#xff0c;则需要卸载之前的版本——解决方式&#xff0c;安装Anaconda 通过百度网盘分享的文件&#xff1a;Anaconda3-2021.05-Linux-x86_64.sh 链接&#xff1a;https://…