一、前言

在QTableView、QTreeView以及对于衍生的QTableWidget、QTreeWidget类中,需要用到自定义委托的情形很多,比如提供下拉框选择,进度条展示下载进度啥的,默认的单元格是没有这些效果的,需要自己单独用委托的形式来展示,自定义委托一般有两种UI形式,一种是单元格一直显示对应的委托控件比如复选框、按钮、进度条等,一种是用户鼠标按下才显示对应的委托控件,鼠标离开自动恢复原有单元格的形式。

在设计这个委托类的时候,综合考虑了很多应用场景需求,例如复选框、文本框、下拉框、日期框、微调框、进度条等都支持,而且就合并在一个类中,方便直接new使用,通过函数指定不同的委托类型即可,也经过大量的项目实战应用,逐步完善到现在的程度。

自定义委托全家桶特点:

  1. 可设置多种委托类型,例如复选框、文本框、下拉框、日期框、微调框、进度条等。
  2. 可设置是否密文显示,一般用于文本框。
  3. 可设置是否允许编辑,一般用于下拉框。
  4. 可设置是否禁用,一般用来禁用某列。
  5. 可设置数据集合,比如下拉框数据集合。
  6. 提供值变化信号,比方说下拉框值改动触发。
  7. 可设置数据校验自动产生不同的图标。
  8. 支持设置校验列、校验规则、校验值、校验成功图标、校验失败图标、图标大小。
  9. 可设置校验数据产生不同的背景颜色和文字颜色。
  10. 校验规则支持 == > >= < <= != contains,非常丰富。
  11. 复选框自动居中而不是左侧,切换选中状态发送对应的信号。
  12. 可设置颜色委托,自动根据颜色值绘制背景颜色,自动设置最佳文本颜色。
  13. 可设置按钮委托,自动根据值生成多个按钮,按钮按下发送对应的信号。
  14. 当设置了委托列时自动绘制选中背景色和文字颜色。
  15. 可设置关键字对照表绘制关键字比如原始数据是 0-禁用 1-启用。
  16. 可设置复选框对应的映射选中不选中关键字。
  17. 根据不同的委托类型绘制,可以依葫芦画瓢自行增加自己的委托。
  18. 所有功能封装成1个类,核心代码不到500行,使用极其方便友好。

自定义委托全家桶应用场景:

  1. 某个字段需要提供下拉框进行选择,下拉框可选是否允许编辑。
  2. 某个字段需要提供密码框进行输入,密文显示字段值。
  3. 某个字段需要提供日期框下拉选择日期时间。
  4. 某个字段需要提供微调框设定值。
  5. 某个字段需要提供进度条显示字段值。
  6. 某个字段列需要禁用。
  7. 各种委托控件可以设置初始的数据集合,比如下拉框。
  8. 各种委托控件在值发生变化的时候发出valuechanged信号,比如下拉框选择声音文件的时候进行播放试听,微调框值改变的时候联动其他控件进行处理等。
  9. 某个字段根据设定的规则进行数据校验自动产生不同的图标显示,比如报警红色图标/正常绿色图标,一目了然。同时可设置校验列/校验规则/校验值/校验成功图标/校验失败图标/图标大小。
  10. 某个字段根据设定的规则进行数据校验自动绘制不同的背景颜色醒目显示,可设定规则包括 == > >= < <= != contains,可设置符合要求的内容文字颜色/背景颜色。
  11. 某个字段需要根据内容显示复选框(自动居中),比如内容是 0/禁用/false 等复选框不选中,1/启用/true 等复选框选中,具体选中不选中对应的内容可自定义。
  12. 某个字段需要根据内容重新替换显示成自定义的内容,比如值是0而需要显示成“不符合”字样,1显示成“符合”字样。对应的内容替换规则可设置关键字对照表。
  13. 某个字段需要根据颜色值显示对应的颜色,同时可以单击选中进行颜色选择。
  14. 某列需要显示操作按钮,按钮的个数/文字集合可设定,根据设定的文字集合平分宽度绘制按钮,单击某个按钮发送对应的按钮单击信号,带按钮索引以及行列,用于用户自行处理。
  15. 一个类通用所有需要委托的场景,相当于一个轮子用在所有项目中,不需要单独再去写不同的委托类。
  16. 一个类通用所有支持委托的控件,比如QTableView/QTableWidget/QListView/QTreeWidget/QListWidget等。

关于Qt数据库相关开发的一些经验总结:

https://qtchina.blog.csdn.net/article/details/119022424

二、功能特点

  1. 同时支持多种数据库比如odbc、sqlite、mysql、postgresql、sqlserver、oracle、人大金仓等。
  2. 一个数据库类即可管理本地数据库通信,也支持远程数据库通信等。
  3. 数据库线程支持执行各种sql语句,包括单条和批量。
  4. 组件中的所有类打印信息、错误信息、执行结果都信号发出去。
  5. 集成数据库通用翻页类(负责具体处理逻辑),搭配分页导航控件(负责外观),形成超级牛逼的翻页控件。
  6. 集成数据库自动清理类,设定最大记录数后台自动清理早期数据。
  7. 集成自定义委托类,支持复选框、文本框、下拉框、日期框、微调框、进度条等。
  8. 同时支持Qt4-Qt6,亲测Qt4.6到Qt6.3任意版本,任意系统和编译器。
  9. 本组件无故障 360天7乘24小时 运行在至少上万个现场,商业级别品质保证。
  10. 每个类都对应完整详细的使用示例,注释详细,非常适合阅读学习。
  11. 可以作为独立的程序运行,比如自动清理早期数据,同步数据到云端。
  12. 全部线程处理,不卡界面,自动重连数据库。
  13. 普通测试情况,sqlite数据库,数据库发生器每秒钟插入1000条记录约0.003秒钟,同时自动清理数据类每秒钟删除1000条记录约0.13秒,不同线程互不干扰。

三、体验地址

  1. 体验地址:https://pan.baidu.com/s/1ZxG-oyUKe286LPMPxOrO2A 提取码:o05q 文件名:bin_dbtool.zip
  2. 国内站点:https://gitee.com/feiyangqingyun
  3. 国际站点:https://github.com/feiyangqingyun
  4. 个人主页:https://blog.csdn.net/feiyangqingyun
  5. 知乎主页:https://www.zhihu.com/people/feiyangqingyun/

四、效果图

五、相关代码

  1. #include "frmdbdelegate.h"
  2. #include "ui_frmdbdelegate.h"
  3. #include "quihelper.h"
  4. #include "dbdelegate.h"
  5. #include "dbconnthread.h"
  6. frmDbDelegate::frmDbDelegate(QWidget *parent) : QWidget(parent), ui(new Ui::frmDbDelegate)
  7. {
  8. ui->setupUi(this);
  9. this->initForm();
  10. }
  11. frmDbDelegate::~frmDbDelegate()
  12. {
  13. delete ui;
  14. }
  15. void frmDbDelegate::showEvent(QShowEvent *)
  16. {
  17. static bool isShow = false;
  18. if (!isShow) {
  19. isShow = true;
  20. QTimer::singleShot(100, this, SLOT(initDb()));
  21. QTimer::singleShot(500, this, SLOT(initData()));
  22. }
  23. }
  24. void frmDbDelegate::initForm()
  25. {
  26. QUIHelper::initTableView(ui->tableView, 25, false, true);
  27. //实例化数据库通信类
  28. dbConn = new DbConnThread(this);
  29. dbConn->setDbFlag("委托");
  30. connect(dbConn, SIGNAL(debug(QString)), this, SLOT(debug(QString)));
  31. connect(dbConn, SIGNAL(error(QString)), this, SLOT(error(QString)));
  32. }
  33. void frmDbDelegate::initDb()
  34. {
  35. DbInfo dbInfo;
  36. //强制本程序带的数据库 dbtool.db
  37. dbInfo.dbName = DbHelper::getDbDefaultFile();
  38. dbConn->setConnInfo(DbHelper::getDbType("sqlite"), dbInfo);
  39. if (!dbConn->openDb()) {
  40. QUIHelper::showMessageBoxError("委托数据库打开失败!");
  41. }
  42. }
  43. void frmDbDelegate::initData()
  44. {
  45. if (!dbConn->getOk()) {
  46. return;
  47. }
  48. model = new QSqlTableModel(this);
  49. model->setTable("UserInfo");
  50. model->setSort(0, Qt::AscendingOrder);
  51. model->setEditStrategy(QSqlTableModel::OnManualSubmit);
  52. model->select();
  53. ui->tableView->setModel(model);
  54. ui->tableView->setProperty("model", true);
  55. QList<QString> columnNames;
  56. columnNames << "用户名称" << "用户密码" << "用户类型" << "模块A" << "模块B" << "模块C" << "模块D" << "模块E" << "模块F" << "模块G" << "备注";
  57. QList<int> columnWidths;
  58. columnWidths << 100 << 120 << 80 << 60 << 60 << 60 << 60 << 60 << 60 << 60 << 60;
  59. int count = columnNames.count();
  60. for (int i = 0; i < count; i++) {
  61. model->setHeaderData(i, Qt::Horizontal, columnNames.at(i));
  62. ui->tableView->setColumnWidth(i, columnWidths.at(i));
  63. }
  64. //用户密码委托
  65. DbDelegate *d_txt_userPwd = new DbDelegate(this);
  66. d_txt_userPwd->setDelegateType("QLineEdit");
  67. d_txt_userPwd->setDelegatePwd(true);
  68. d_txt_userPwd->setDelegateColumn(1);
  69. ui->tableView->setItemDelegateForColumn(1, d_txt_userPwd);
  70. //用户类型委托
  71. QStringList userType;
  72. userType << "操作员" << "管理员";
  73. DbDelegate *d_cbox_userType = new DbDelegate(this);
  74. d_cbox_userType->setDelegateType("QComboBox");
  75. d_cbox_userType->setDelegateValue(userType);
  76. ui->tableView->setItemDelegateForColumn(2, d_cbox_userType);
  77. //启用禁用委托
  78. for (int i = 3; i < (3 + 7); i++) {
  79. DbDelegate *d_ckbox_userAdmin = new DbDelegate(this);
  80. d_ckbox_userAdmin->setDelegateColumn(i);
  81. d_ckbox_userAdmin->setDelegateType("QCheckBox");
  82. d_ckbox_userAdmin->setCheckBoxText("启用", "禁用");
  83. ui->tableView->setItemDelegateForColumn(i, d_ckbox_userAdmin);
  84. }
  85. }
  86. void frmDbDelegate::debug(const QString &msg)
  87. {
  88. }
  89. void frmDbDelegate::error(const QString &msg)
  90. {
  91. }
  92. void frmDbDelegate::on_btnAdd_clicked()
  93. {
  94. int count = model->rowCount();
  95. model->insertRow(count);
  96. QString userName = model->index(count - 1, 0).data().toString();
  97. QString userPwd = model->index(count - 1, 1).data().toString();
  98. QString userType = model->index(count - 1, 2).data().toString();
  99. QString userAdmin1 = model->index(count - 1, 3).data().toString();
  100. QString userAdmin2 = model->index(count - 1, 4).data().toString();
  101. QString userAdmin3 = model->index(count - 1, 5).data().toString();
  102. QString userAdmin4 = model->index(count - 1, 6).data().toString();
  103. QString userAdmin5 = model->index(count - 1, 7).data().toString();
  104. QString userAdmin6 = model->index(count - 1, 8).data().toString();
  105. QString userAdmin7 = model->index(count - 1, 9).data().toString();
  106. QString userMark = model->index(count - 1, 10).data().toString();
  107. //设置新增加的行默认值
  108. model->setData(model->index(count, 0), userName);
  109. model->setData(model->index(count, 1), userPwd);
  110. model->setData(model->index(count, 2), userType);
  111. model->setData(model->index(count, 3), userAdmin1);
  112. model->setData(model->index(count, 4), userAdmin2);
  113. model->setData(model->index(count, 5), userAdmin3);
  114. model->setData(model->index(count, 6), userAdmin4);
  115. model->setData(model->index(count, 7), userAdmin5);
  116. model->setData(model->index(count, 8), userAdmin6);
  117. model->setData(model->index(count, 9), userAdmin7);
  118. model->setData(model->index(count, 10), userMark);
  119. ui->tableView->setCurrentIndex(model->index(count, 0));
  120. }
  121. void frmDbDelegate::on_btnSave_clicked()
  122. {
  123. model->database().transaction();
  124. if (model->submitAll()) {
  125. model->database().commit();
  126. } else {
  127. model->database().rollback();
  128. qDebug() << TIMEMS << model->database().lastError();
  129. QUIHelper::showMessageBoxError("保存信息失败,请重新填写!");
  130. }
  131. //有些数据库需要主动查询一下不然是空白的比如odbc数据源
  132. model->select();
  133. }
  134. void frmDbDelegate::on_btnDelete_clicked()
  135. {
  136. int row = ui->tableView->currentIndex().row();
  137. if (row < 0) {
  138. QUIHelper::showMessageBoxError("请选择要删除的用户!");
  139. return;
  140. }
  141. if (QUIHelper::showMessageBoxQuestion("确定要删除该用户吗? 删除后不能恢复!") == QMessageBox::Yes) {
  142. QString userName = model->index(row, 0).data().toString();
  143. if (userName == "admin") {
  144. QUIHelper::showMessageBoxError("管理员 [admin] 不能被删除!", 3);
  145. return;
  146. }
  147. model->removeRow(row);
  148. model->submitAll();
  149. ui->tableView->setCurrentIndex(model->index(model->rowCount() - 1, 0));
  150. }
  151. }
  152. void frmDbDelegate::on_btnReturn_clicked()
  153. {
  154. model->revertAll();
  155. }
  156. void frmDbDelegate::on_btnClear_clicked()
  157. {
  158. if (model->rowCount() <= 0) {
  159. return;
  160. }
  161. if (QUIHelper::showMessageBoxQuestion("确定要清空所有用户信息吗?") == QMessageBox::Yes) {
  162. DbHelper::clearTable("UserInfo", AppConfig::LocalDbType);
  163. model->select();
  164. }
  165. }

Qt数据库应用14-超级自定义委托的更多相关文章

  1. Qt自定义委托在QTableView中绘制控件、图片、文字(内容比较全)

    自定义委托,继承于,QStyledItemDelegate类,重载Paint()函数, 1.实现在QTableView中绘制 格式字符串 2.实现在QTableView中绘制进度条 3.实现在QTab ...

  2. Qt自定义委托在QTableView中绘制控件、图片、文字

    自定义委托,继承于,QStyledItemDelegate类,重载Paint()函数, 1.实现在QTableView中绘制 格式字符串 2.实现在QTableView中绘制进度条 3.实现在QTab ...

  3. 26.QT-模型视图之自定义委托

    在上一章学习 25.QT-模型视图 后,本章接着学习视图委托 视图委托(Delegate)简介 由于模型负责组织数据,而视图负责显示数据,所以当用户想修改显示的数据时,就要通过视图中的委托来完成 视图 ...

  4. jdbc 加载数据库驱动如何破坏双亲委托模式

    导读      通过jdbc链接数据库,是每个学习Java web 方向的人必然一开始会写的代码,虽然现在各路框架都帮大家封装好了jdbc,但是研究一下jdbc链接的套路还是很意义     术语以及相 ...

  5. Qt之模型/视图(自定义风格)

    Qt之模型/视图(自定义风格) 关于自定义风格是针对视图与委托而言的,使用事件与QSS都可以进行处理,今天关于美化的细节讲解一下. 先看下图: 先撇开界面的美观性(萝卜青菜,各有所爱),就现有的这些风 ...

  6. QTableWidget自定义委托

    QTableWidget单元格使用自定义的lineEdit控件导致不能选中 使用自定义委托解决 1.自定义委托 class LineEditDelegate : public QItemDelegat ...

  7. 自定义委托类型 - .Net自带委托类型

    委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递. 与其他的类不同,委托类具有一个签名,并且它只能对与其签名匹配的方法进行引用. 一.自定义委托类型 1.语法结构:访问修 ...

  8. EventHandler委托与自定义委托

    http://blog.csdn.net/uuxyz/article/details/7175248 EventHandler委托与自定义委托 自定义委托: //1. public delegate ...

  9. qt数据库多线程问题的解决(QSqlDatabase只能在创建它的线程中使用)

    Qt数据库由QSqlDatabase::addDatabase()生成的QSqlDatabase只能在创建它的线程中使用, 在多线程中共用连接或者在另外一个线程中创建query都是不支持的几乎国内没有 ...

  10. Java数据库设计14个技巧

    Java数据库设计14个技巧   1. 原始单据与实体之间的关系 可以是一对一.一对多.多对多的关系.在一般情况下,它们是一对一的关系:即一张原始单据对应且只对应一个实体.在特殊情况下,它们可能是一对 ...

随机推荐

  1. 云原生周刊:Score 成为 CNCF 沙箱项目|2024.7.15

    开源项目 Trident Trident 是由 NetApp 维护的全面支持的开源项目.它从头开始设计,旨在通过行业标准接口(如容器存储接口 CSI)帮助您满足容器化应用程序对持久性存储的需求. Mo ...

  2. Curve 分布式存储在 KubeSphere 中的实践

    Curve 介绍 Curve 是网易开发的现代存储系统,目前支持文件存储 (CurveFS) 和块存储 (CurveBS).现在它作为一个沙盒项目托管在 CNCF. Curve 是一个高性能.轻量级操 ...

  3. 布局(LinearLayout,RelativeLayout,FrameLayout,TableLayout,GridLayout,ConstraintLayout)

    LinearLayout layout_gravity:组件在父容器里的对齐方式 gravity:组件包含的所有子元素的对齐方式 layout_weight:在原有基础上分配剩余空间,一般把layou ...

  4. FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库

    ijkplayer是一款由B站研发的移动端国产播放器,它基于FFmpeg3.4版本,同时兼容Android和iOS两大移动操作系统.ijkplayer的源码托管地址为https://github.co ...

  5. 浅谈TiKV集群运维问题排查与修复——磁盘空间占用问题

    作者:来自 vivo 互联网存储团队- Yuan Jianwei 本文介绍了 TiKV 磁盘空间问题的排查思路与解决方案. 一.背景介绍 在业务快速扩张的年代,vivo 内部的很多业务为了可以快速上线 ...

  6. 有Redis为什么还要本地缓存?谈谈你对本地缓存的理解?

    本地缓存是将数据存储在应用程序所在的本地内存中的缓存方式.既然,已经有了 Redis 可以实现分布式缓存了,为什么还需要本地缓存呢?接下来,我们一起来看. 为什么需要本地缓存? 尽管已经有 Redis ...

  7. delphi12 Android Edit SDK安装

    安装 delphi 12.1 后,编译 FMX Android 程序失败! 查找原因,SDK配置全是叹号! 之前用过SDK Manager.exe,直接打开即可以选择下载,但现在发现没有了,查找资料如 ...

  8. php使用汉字作为进制转换

    突然想到英文字符26个,大小写共52个,数字10个,加起来也不过62,再算上特殊字符,也就90个,可以看这篇文章 那可不可以扩大这个进制呢?我想到了汉字. 中文汉字,博大精深,我们就用常用汉字2500 ...

  9. Redis中有事务吗?有何不同?

    与关系型数据库事务的区别 Redis事务是指将多条命令加入队列,一次批量执行多条命令,每条命令会按顺序执行,事务执行过程中不会被其他客户端发来的命令所打断.也就是说,Redis事务就是一次性.顺序性. ...

  10. pydotplus使用

    pydotplus是别的语言嫁接到python里面的,所以绘制要传入字符串形式表示的结构,而没有python的结构对象直接用来画.代码如下: import pydotplus as pdp graph ...