向QAbstractItemView子类如:QTreeView、QTableView等子项单元格插入窗体小部件的功能实现(第2种方法)

news2025/1/10 17:45:48

1.前言

工作中经常会遇到这样的需求:向QAbstractItemView子类如QTreeView、QTableView单元格插入窗体小部件,如:进度条、按钮、单行编辑框等。下面链接的系列博文就是讲解如何实现该功能的。

  • 《向QAbstractItemView子类如:QTreeView、QTableView等子项单元格插入窗体小部件的功能实现(第1种方法)》。

  • 《向QAbstractItemView子类如:QTreeView、QTableView等子项单元格插入窗体小部件的功能实现(第2种方法)》。

  • 《向QAbstractItemView子类如:QTreeView、QTableView等子项单元格插入窗体小部件的功能实现(第3种方法)》。

这些系列博文所说的技术点适用于同时满足下面条件的所有类:

  • 模型类从 QAbstractItemModel派生。

  • 代理类从QStyledItemDelegate或QItemDelegate派生。

  • 视图类是QAbstractItemView的子类。

这些系列博文用到了Qt的model/view framework框架,如果对Qt的“模型/视图/代理”框架不懂,这些系列文章很难读懂。如果不懂这方面的知识,请在Qt Assistant 中输入Model/View Programming 学习了解。读者本机Qt安装目录下的Examples\Qt-XX.XX.XX\widgets\itemviews目录下有很多model/view framework的例子,可以进行自学了解,其中XX.XX.XX为Qt的版本号,如:5.14.1。

因为QColumnView、QHeaderView、QListView、QTableView、QTreeView、QListWidget 、QUndoView、QTableWidget、QTreeWidget都是从QAbstractItemView继承,故上面链接的博文所说的技术点也适用于这些类。

本博文通过Qt的QStyledItemDelegate或QItemDelegate类再结合QStyle类相关函数如:drawControl来实现向视图单元格插入窗体小部件功能。

2.实现详解

说明:下述所贴源码的.h文件请从cpp文件中自己抠出,不再贴.h文件。

以表格视图为例说明,其它从QAbstractItemView派生的子类视图和表格视图类似。先实现表格视图类的数据模型类,如下为model.cpp的实现:

#include "model.h"
CModel::CModel(QObject* parent)
    : QAbstractTableModel(parent)
{}

CModel::~CModel()
{}

// 作为例子,不设置每个项的数据
QVariant CModel::data(const QModelIndex& index, int role/* = Qt::DisplayRole*/) const
{
    return QVariant();
}

// 作为例子,假想QTableView有3列
int CModel::columnCount(const QModelIndex& parent/* = QModelIndex()*/) const
{
    return 3;
}

// 作为例子,假想QTableView有88行
int CModel::rowCount(const QModelIndex& parent/* = QModelIndex()*/) const
{
    return 88;
}

QVariant CModel::headerData(int section, Qt::Orientation orientation, int role /*= Qt::DisplayRole*/) const
{
    if (orientation != Qt::Horizontal) // 作为例子演示,我们只关心表头是水平的情况
        return QVariant();

    if (role != Qt::DisplayRole)// 作为例子演示,我们只关心 Qt::DisplayRole
        return QVariant();

    // 构造列,第1列列名为"button";第2列列名为"checkbox",第3列列名为"Slider"
    if (0 == section)
        return "button";
    else if (1 == section)
        return "checkbox";
    else if (2 == section)
        return "Slider";

    return QVariant();
}

再实现表格视图的代理类,如下:

#include "tvItemDelegate.h"
#include <QStyleOptionButton> 
#include<QApplication>
CTVItemDelegate::CTVItemDelegate(QObject* parent /*= nullptr*/)
{

}
CTVItemDelegate::~CTVItemDelegate()
{

}

void CTVItemDelegate::drawPushButton(QPainter* painter, const QStyleOptionViewItem& option, const QString&qsWndText) const
{
    QStyleOptionButton styleOptBtn;
    styleOptBtn.rect = option.rect; // 设置按钮占据的矩形
    styleOptBtn.icon = qApp->style()->standardIcon(QStyle::SP_DesktopIcon); // 设置按钮图标
    styleOptBtn.iconSize = QSize(32, 32);// 设置按钮图标尺寸
    styleOptBtn.text = QString("button%1").arg(qsWndText);// 设置按钮标题
    styleOptBtn.state = QStyle::State_Enabled | QStyle::State_Raised; // 设置按钮状态
    styleOptBtn.direction = Qt::LeftToRight; // 设置按钮水平布局,如果改为Qt::RightToLeft,则按钮图标在按钮标题右侧。
    styleOptBtn.features = QStyleOptionButton::None | QStyleOptionButton::Flat;// 设置按钮风格特点为普通扁平按钮
    qApp->style()->drawControl(QStyle::CE_PushButton, &styleOptBtn, painter); // 绘制按钮
}

void CTVItemDelegate::drawCheckBox(QPainter* painter, const QStyleOptionViewItem& option, const QString& qsWndText) const
{
    QStyleOptionButton styleOptBtn;
    styleOptBtn.rect = option.rect;// 设置按钮占据的矩形
    styleOptBtn.icon = qApp->style()->standardIcon(QStyle::SP_DesktopIcon);// 设置按钮图标
    styleOptBtn.iconSize = QSize(32, 32);
    styleOptBtn.text = QString("CheckBox%1").arg(qsWndText);// 设置复选按钮标题
    styleOptBtn.state = QStyle::State_Enabled | QStyle::State_Raised;// 设置按钮状态
    styleOptBtn.direction = Qt::LeftToRight; // 设置按钮水平布局,如果改为Qt::RightToLeft,则按钮图标在按钮标题右侧。
    styleOptBtn.features = QStyleOptionButton::None | QStyleOptionButton::Flat;// 设置按钮风格特点为普通扁平按钮
    qApp->style()->drawControl(QStyle::CE_CheckBox, &styleOptBtn, painter);// 绘制按钮
}

void CTVItemDelegate::drawSlider(QPainter* painter, const QStyleOptionViewItem& option) const
{
    QStyleOptionSlider styleOptnSlider;
    styleOptnSlider.rect = option.rect;// 设置按钮占据的矩形
    styleOptnSlider.state = QStyle::State_Enabled;// 设置按钮状态
    styleOptnSlider.minimum = 0; // 设置滑块最小值
    styleOptnSlider.maximum = 100;// 设置滑块最大值
    styleOptnSlider.sliderPosition = 50;// 设置滑块当前值
    qApp->style()->drawComplexControl(QStyle::CC_Slider, &styleOptnSlider, painter); // 绘制滑杆控件
}

void CTVItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
    if (!index.isValid())
    {
        return;
    }

    auto nRowIndex = index.row();
    auto nColIndex = index.column();
    auto wndText = QString("%1").arg(nRowIndex);
    switch (nColIndex)
    {
    case 0:
    {
        drawPushButton(painter, option, wndText);
    }
    break;
    case 1:
    {
        drawCheckBox(painter, option, wndText);
    }
    break;
    case 2:
    {
        drawSlider(painter, option);
    }
    break;
    default:
        break;
    }
     
}

最后将设置表格视图模型、代理:

#include "QtWidgetsApplication1.h"
#include "model.h"
#include "tvItemDelegate.h"

QtWidgetsApplication1::QtWidgetsApplication1(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);
    auto pModel = new CModel(this);

    // 为表视图设置数据模型
    ui.tableView->setModel(pModel); 

    // 为表视图设置代理类
    ui.tableView->setItemDelegate(new CTVItemDelegate(this));

    ui.tableView->setColumnWidth(0, 200);
    ui.tableView->setColumnWidth(1, 200);
    ui.tableView->setColumnWidth(2, 200);
}

效果如下:

3.附加说明

3.1.窗体小部件相应鼠标事件的实现

上述只是实现了插入窗体小部件,但发现按钮、滑杆等鼠标单击都没反应。这可以自己来实现,大体思路是:

  1. 重载代理类的如下函数:

[override virtual protected] bool QStyledItemDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
  1. 在editorEvent函数中的option参数中的option.rect判断出鼠标单击事件发生在哪个单元格,从而找到是哪个窗体小部件。

  1. 自定义一个信号,表示小部件被鼠标单击了。

  1. 在视图类中绑定3步骤中的自定义信号,并调用视图的update函数更新视图。

具体可参考《QAbstractItemView子类如:QTreeView、QTableView等子项单元格复选框勾选/取消勾选功能实现》。

3.2.普通窗体部件、复杂窗体部件绘制的不同说明

上述可以看到普通窗体部件是通过drawControl函数绘制的;而复杂窗体控件是通过drawComplexControl函数绘制的。关于普通窗体部件、复杂窗体部件绘制的不同及这两个函数的含义,请参见《QStyle类用法总结(二)》博文的4.2、4.3节描述。QStyle::CC_Slider、QStyle::CE_CheckBox、QStyle::CE_PushButton各枚举值的含义,请参见《QStyle类用法总结(三)》中的2.2节或Qt Assist。

3.3.可绘制在单元格中的QStyleOption子类

QStyleOption子类如下:

虽然说理论上这些子类都可以被绘制在视图的单元格中,但现实中往往由于单元格高度一般不是很高,再加上业务的需求,所以常用的为:QStyleOptionButton(按钮、复选按钮、单选按钮)、QStyleOptionComboBox(组合框), QStyleOptionGroupBox(组框) , QStyleOptionSlider(滑竿条), QStyleOptionSpinBox(上下翻值框), QStyleOptionToolButton(工具按钮)、 QStyleOptionFocusRect(带焦点的矩形)、QStyleOptionProgressBar(进度条)。

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

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

相关文章

LeetCode 2500. 删除每行中的最大值

给你一个 m x n 大小的矩阵 grid &#xff0c;由若干正整数组成。 执行下述操作&#xff0c;直到 grid 变为空矩阵&#xff1a; 从每一行删除值最大的元素。如果存在多个这样的值&#xff0c;删除其中任何一个。 将删除元素中的最大值与答案相加。 注意 每执行一次操作&#…

行为型模式-状态模式

1.概述 【例】通过按钮来控制一个电梯的状态&#xff0c;一个电梯有开门状态&#xff0c;关门状态&#xff0c;停止状态&#xff0c;运行状态。每一种状态改变&#xff0c;都有可能要根据其他状态来更新处理。例如&#xff0c;如果电梯门现在处于运行时状态&#xff0c;就不能…

时序数据处理中的拟合问题

对于深度学习或机器学习模型而言,我们不仅要求它对训练数据集有很好的拟合(训练误差),同时也希望它可以对未知数据集(测试集)有很好的拟合结果(泛化能力),所产生的测试误差被称为泛化误差。度量泛化能力的好坏,最直观的表现就是模型的过拟合(overfitting)和欠拟合(…

一起Talk Android吧(第四百七十五回:渐变类视图动画)

文章目录使用方法属性介绍示例代码共用属性各位看官们大家好&#xff0c;上一回中咱们说的例子是"如何使用视图动画",这一回中咱们说的例子是"渐变类视图动画"。闲话休提&#xff0c;言归正转&#xff0c;让我们一起Talk Android吧&#xff01; 看官们&am…

移动web动画

移动web动画动画动画属性鼠标经过暂停动画多组动画鼠标经过暂停动画多组动画动画 动画最大的特点可以不用鼠标触发&#xff0c;自动的&#xff0c;反复的执行某些动画。 动画使用分为定义和调用&#xff1a; 定义&#xff1a; /* 1. 定义的动画 */ keyframes dance {from {tr…

恶意代码分析实战 12 对抗反汇编

12.1 Lab15-01 问题 这个二进制程序中使用了何种对抗反汇编技术&#xff1f; 首先&#xff0c;使用IDA载入该文件。 我们可以看到这个程序在地址0040100E处存在一个对抗反汇编技术的痕迹。 eax总是被置为零&#xff0c;jz跳转总是被执行。所以我们认为这一行是假冒的call指…

Docker的架构设计

前面我们研究了Docker容器的本质是一个特殊的进程&#xff0c;那么这个特殊进程是如何创建、如何终止的那&#xff1f;也就是说是谁来管理这个容器进程的生命周期的那&#xff1f;在mac操作系统中我们可以通过活动监视器来观察操作系统里面有哪些进程&#xff0c;以及通过活动监…

推荐算法:序列召回

目录 序列召回&#xff08;一&#xff09; 序列召回&#xff08;二&#xff09; 序列召回&#xff08;三&#xff09; 序列召回&#xff08;四&#xff09; 序列召回&#xff08;一&#xff09; 源自论文&#xff1a;http://arxiv.org/abs/1511.06939 基于GRU的序列召回中通过…

青训营项目实战1

项目实战 实现掘金青训营报名页码的后端部分 需求描述 展示话题&#xff08;标题、文字描述&#xff09;和回帖列表 不考虑前端页面实现&#xff0c;仅实现一个本地web服务 话题和回帖数据用文件存储 附加要求&#xff1a; 支持发布帖子 本地id生成要保证不重复 append文件 更…

【ONE·C || 指针】

总言 C语言&#xff1a;指针的使用介绍。 文章目录总言1、指针初阶1.1、是什么1.2、指针和指针类型1.2.1、指针类型介绍1.2.2、作用一&#xff1a;指针解引用1.2.3、作用二&#xff1a;指针整数1.3、野指针1.3.1、野指针是什么1.3.2、为什么存在野指针1.3.3、如何避免野指针1.4…

ReentrantLock从入门到踢门

1. ReentrantLock是什么Lock提供了比synchronized方法和语句更广泛的锁定操作。 更灵活的结构化&#xff0c;并且支持多个相关联的对象Condition。它实现了Lock、Serializable序列化接口。图1 ReentrantLock实现接口图1.1 Lock1.1.1 lock// 获取锁 void lock();1.1.2 lockInter…

SpringMVC -->ant风格的路径 -->占位符 -->获取请求参数 -->@RequestParam

文章目录SpringMVC支持ant风格的路径SpringMVC支持路径中的占位符SpringMVC获取请求参数通过servletAPI获取通过控制器方法的形参获取请求参数RequestParam注解处理请求参数和控制器方法的形参的映射关系代码样例SpringMVC支持ant风格的路径 &#xff1f;&#xff1a;表示任意的…

爆火微信公众号自定义早安推送,爱她就给她推送

为女朋友打造专属早安推送先上截图电脑端看的效果手机端看的效果一、申请微信公众号测试号二、让他/她扫码关注测试公众号三、新增模板消息四、天气API五、使用 leancloud 部署云函数六、源代码先上截图 电脑端看的效果 手机端看的效果 一、申请微信公众号测试号 https://mp.w…

Kettle(7):插入/更新组件

1 组件介绍 插入/更新组件能够将Kettle抽取的数据&#xff0c;与某个表的数据进行对比&#xff0c;如果数据存在就更新&#xff0c;不存在就插入。 2 需求 修改 t_user中的张三这一行数据&#xff0c;修改age为80 同时&#xff0c;我们想要使用Kettle将 t_user1 中的张三这一…

【编程入门】N种编程语言做个记事本

背景 前面已输出多个系列&#xff1a; 《十余种编程语言做个计算器》 《十余种编程语言写2048小游戏》 《17种编程语言10种排序算法》 《十余种编程语言写博客系统》 《十余种编程语言写云笔记》 本系列对比云笔记&#xff0c;将更为简化&#xff0c;去掉了网络调用&#xff0…

量化选股——基于多因子模型的量化策略(第1部分—因子测算策略构建)

文章目录1.多因子模型概述2.因子挖掘3.多因子策略4.多因子策略构建基于多因子的策略通用流程Fama-French三因子因子效果测算方法因子测算结论&量化策略构建东西有点多&#xff0c;拆开成多个文章&#xff0c;边写边整合~&#xff0c;应该会分成2部分&#xff1a; 第1部分—…

【每日一道智力题】之坤坤猜生日(面试高频)

&#x1f680;write in front&#x1f680; &#x1f4dc;所属专栏&#xff1a;每日一题 &#x1f6f0;️博客主页&#xff1a;睿睿的博客主页 &#x1f6f0;️代码仓库&#xff1a;&#x1f389;VS2022_C语言仓库 &#x1f3a1;您的点赞、关注、收藏、评论&#xff0c;是对我最…

文本特征工程——下篇

文本特征下篇 针对梯度提升树模型对文本特征进行特征工程&#xff0c;我们需要充分挖掘LabelLabelLabel编码丢失信息&#xff0c;例如上面的名字特征。内部存在非常强的规律&#xff0c;Mr等信息。这些信息反映了性别相关的信息。如果直接进行Label编码就会丢失此类信息&#…

高通平台开发系列讲解(GPS篇)NMEA数据包解析

文章目录 一、通用NMEA语句类型二、 NMEA语句格式2.1、GSV语句2.2、RMC语句2.3、GSA语句2.4、VTG语句2.5、DTM语句2.6、GNS语句2.7、GGA语句2.8、GLL语句2.9、GST语句2.10、ZDA语句沉淀、分享、成长,让自己和他人都能有所收获!😄 📢 NMEA-0183是美国国家海洋电子协会为海…

【读论文】Going deeper in spiking neural networks Vgg and residual architecture

frontiers in Neuroscience 2019 摘要 本文提出一种新的方法来构建深度SNN&#xff0c;并在复杂视觉识别问题上证明其有效性&#xff08;如CIFAR10和ImageNet&#xff09;&#xff1b;该方法应用于VGG和残差网络结构&#xff0c;并获得最优精度&#xff1b;最后给出稀疏事件驱…