C++ Qt开发:QItemDelegate自定义代理组件

老规矩,首先推荐好书:

Qt 是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍QStyledItemDelegate自定义代理组件的常用方法及灵活运用。

在Qt中,QStyledItemDelegate 类是用于创建自定义表格视图(如QTableViewQTableWidget)的委托类,允许你自定义表格中每个单元格的外观和交互。QStyledItemDelegateQItemDelegate 的子类,提供了更现代、更易用的接口。此处我们将实现对QTableView表格组件的自定义代理功能,例如默认情况下表格中的缺省代理就是一个编辑框,我们只能够在编辑框内输入数据,而有时我们想选择数据而不是输入,此时就需要重写编辑框实现选择的效果,代理组件常用于个性化定制表格中的字段类型。

1.1 概述代理类

代理类的作用是用来实现组件重写的,例如TableView中默认是可编辑的,之所以可编辑是因为Qt默认为我们重写了QLineEdit编辑框实现的,也可理解为将组件嵌入到了表格中,实现了对表格的编辑功能。

在自定义代理中QAbstractItemDelegate是所有代理类的抽象基类,它用于创建自定义的项委托。提供了一个基本的框架,使得可以定制如何在视图中绘制和编辑数据项。

QAbstractItemDelegateQItemDelegate 的基类,而 QItemDelegate 则是 QStyledItemDelegate 的基类。这个继承体系提供了不同层次的定制能力。我们继承任何组件时都必须要包括如下4个函数:

  • CreateEditor() 用于创建编辑模型数据的组件,例如(QSpinBox组件)
  • SetEditorData() 从数据模型获取数据,以供Widget组件进行编辑
  • SetModelData() 将Widget组件上的数据更新到数据模型
  • UpdateEditorGeometry() 给Widget组件设置一个合适的大小

通过继承 QAbstractItemDelegate 并实现这些函数,读者可创建一个定制的项委托,用于控制数据项在视图中的外观和交互行为。此处我们分别重写三个代理接口,其中两个ComBox组件用于选择婚否,而第三个SpinBox组件则用于调节数值范围,先来定义三个重写部件。

1.2 自定义代理组件

这里我们以第一个SpinBox组件为例,要实现代理该组件,首先需要在项目上新建一个SpinDelegate类,并依次实现上述的四个方法,先来开创建流程;

  • 选择addnew选中 C++ Class 输入自定义类名称QWintSpinDelegate,然后基类继承QStyledItemDelegate/QMainWindow,然后下一步结束向导,同理其他功能的创建也如此。

接着就是对该接口的重写了,此处重写代码spindelegate.cpp如下所示,其关键位置的解释可参考注释部分。

#include "spindelegate.h"
#include <QSpinBox>

QWIntSpinDelegate::QWIntSpinDelegate(QObject *parent):QStyledItemDelegate(parent)
{
}

// 创建代理编辑组件
QWidget *QWIntSpinDelegate::createEditor(QWidget *parent,const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    Q_UNUSED(option);
    Q_UNUSED(index);

    QSpinBox *editor = new QSpinBox(parent);  // 创建一个QSpinBox
    editor->setFrame(false);                  // 设置为无边框
    editor->setMinimum(0);
    editor->setMaximum(10000);
    return editor;                            // 返回此编辑器
}

// 从数据模型获取数据,显示到代理组件中
void QWIntSpinDelegate::setEditorData(QWidget *editor,const QModelIndex &index) const
{
    // 获取数据模型的模型索引指向的单元的数据
    int value = index.model()->data(index, Qt::EditRole).toInt();

    QSpinBox *spinBox = static_cast<QSpinBox*>(editor);   // 强制类型转换
    spinBox->setValue(value);                             // 设置编辑器的数值
}

// 将代理组件的数据,保存到数据模型中
void QWIntSpinDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
    QSpinBox *spinBox = static_cast<QSpinBox*>(editor); // 强制类型转换
    spinBox->interpretText();                           // 解释数据,如果数据被修改后,就触发信号
    int value = spinBox->value();                       // 获取spinBox的值
    model->setData(index, value, Qt::EditRole);         // 更新到数据模型
}

// 设置组件大小
void QWIntSpinDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    Q_UNUSED(index);
    editor->setGeometry(option.rect);
}
 

接着重写接口floatspindelegate.cpp实现代码如上述部分一致,唯一的变化是组件变了,代码如下;

#include "floatspindelegate.h"
#include <QDoubleSpinBox>

QWFloatSpinDelegate::QWFloatSpinDelegate(QObject *parent):QStyledItemDelegate(parent)
{
}

QWidget *QWFloatSpinDelegate::createEditor(QWidget *parent,
   const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    Q_UNUSED(option);
    Q_UNUSED(index);

    QDoubleSpinBox *editor = new QDoubleSpinBox(parent);
    editor->setFrame(false);
    editor->setMinimum(0);
    editor->setDecimals(2);
    editor->setMaximum(10000);

    return editor;
}

void QWFloatSpinDelegate::setEditorData(QWidget *editor,
                      const QModelIndex &index) const
{
    float value = index.model()->data(index, Qt::EditRole).toFloat();
    QDoubleSpinBox *spinBox = static_cast<QDoubleSpinBox*>(editor);
    spinBox->setValue(value);
}

void QWFloatSpinDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
    QDoubleSpinBox *spinBox = static_cast<QDoubleSpinBox*>(editor);
    spinBox->interpretText();
    float value = spinBox->value();
    QString str=QString::asprintf("%.2f",value);

    model->setData(index, str, Qt::EditRole);
}

void QWFloatSpinDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    editor->setGeometry(option.rect);
}
 

最后重写接口comboxdelegate.cpp其代码如下所示;

#include "comboxdelegate.h"
#include <QComboBox>

QWComboBoxDelegate::QWComboBoxDelegate(QObject *parent):QItemDelegate(parent)
{

}

QWidget *QWComboBoxDelegate::createEditor(QWidget *parent,const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    QComboBox *editor = new QComboBox(parent);

    editor->addItem("已婚");
    editor->addItem("未婚");
    editor->addItem("单身");

    return editor;
}

void QWComboBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
    QString str = index.model()->data(index, Qt::EditRole).toString();

    QComboBox *comboBox = static_cast<QComboBox*>(editor);
    comboBox->setCurrentText(str);
}

void QWComboBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
    QComboBox *comboBox = static_cast<QComboBox*>(editor);
    QString str = comboBox->currentText();
    model->setData(index, str, Qt::EditRole);
}

void QWComboBoxDelegate::updateEditorGeometry(QWidget *editor,const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    editor->setGeometry(option.rect);
}
 

将部件导入到mainwindow.cpp主程序中,并将其通过ui->tableView->setItemDelegateForColumn(0,&intSpinDelegate);关联部件到指定的table下标索引上面。

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    // 初始化模型数据
    model = new QStandardItemModel(4,6,this);      // 初始化4行,每行六列
    selection = new QItemSelectionModel(model);    // 关联模型

    ui->tableView->setModel(model);
    ui->tableView->setSelectionModel(selection);

    // 添加表头
    QStringList HeaderList;
    HeaderList << "序号" << "姓名" << "年龄" << "性别" << "婚否" << "薪资";
    model->setHorizontalHeaderLabels(HeaderList);

    // 批量添加数据
    QStringList DataList[3];
    QStandardItem *Item;

    DataList[0] << "1001" << "admin" << "24" << "男" << "已婚" << "4235.43";
    DataList[1] << "1002" << "guest" << "23" << "男" << "未婚" << "20000.21";
    DataList[2] << "1003" << "lucy" << "37" << "女" << "单身" << "8900.23";

    int Array_Length = DataList->length();                          // 获取每个数组中元素数
    int Array_Count = sizeof(DataList) / sizeof(DataList[0]);       // 获取数组个数

    for(int x=0; x<Array_Count; x++)
    {
        for(int y=0; y<Array_Length; y++)
        {
            // std::cout << DataList[x][y].toStdString().data() << std::endl;
            Item = new QStandardItem(DataList[x][y]);
            model->setItem(x,y,Item);
        }
    }

    // 为各列设置自定义代理组件
    // 0,4,5 代表第几列 后面的函数则是使用哪个代理类的意思
    ui->tableView->setItemDelegateForColumn(0,&intSpinDelegate);
    ui->tableView->setItemDelegateForColumn(4,&comboBoxDelegate);
    ui->tableView->setItemDelegateForColumn(5,&floatSpinDelegate);
}

MainWindow::~MainWindow()
{
    delete ui;
}
 

运行后,序号部分与薪资部分将变成一个SpinBox组件,读者可自行调节大小,如下图;

而婚否字段将被重写成一个ComBoBox组件,这有助于让用户直接选择一个状态,如下图;

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

程序员如何高效学习技术?

我们相信努力学习一定会有收获&#xff0c;但是方法不当&#xff0c;既让人身心疲惫&#xff0c;也没有切实的回报。 不少朋友每天都阅读技术文章&#xff0c;但是第二天就忘干净了。工作中领导和同事都认可你的沟通和技术能力&#xff0c;但是跳槽面试却屡屡碰壁。面试官问技术…

龙芯loongarch64服务器编译安装scikit-learn

前言 根据我之前的文章介绍&#xff0c;龙芯loongarch64服务器中的很多python依赖包安装有问题&#xff0c;发现其中安装的"scikit-learn"就无法正常使用&#xff0c;会报如下错误No module named sklearn.__check_build._check_build&#xff1a; 解决办法 从第三方…

java keytool.exe ssl

JDK如果没有先安装 JDK8 install_jdk aleady install-CSDN博客 java keytool.exe ssl keytool -genkey -alias tomcat -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore D:\server.keystore -validity 3650 server.ssl.key-storeD:\server.keystore server.ssl.key-…

吉他初学者学习网站搭建系列(6)——如何根据歌名查歌词

文章目录 背景实现track.searchtrack.lyrics.get 效果存在问题 背景 当你想要扒歌时&#xff0c;第一件事就是如何先拿到一首歌的歌词。当然&#xff0c;你可以去复制粘贴&#xff0c;但是如果可以在网站中直接搜到&#xff0c;那就太棒了。 实现 这里用到了国外的API https…

【Redis刨析】知识图谱的构建与实现

前言 「作者主页」&#xff1a;雪碧有白泡泡 「个人网站」&#xff1a;雪碧的个人网站 ChatGPT体验地址 文章目录 前言引用构建过程Redis的知识图谱构建过程Redis介绍快的原因持久化 引用 对于编程的学习&#xff0c;过了初级阶段&#xff0c;我认为应该减少对视频的依赖&am…

主动学习如何解决数据标注的难题?主动学习和弱监督学习有何区别?

机器学习的成功与否取决于数据标注的质量和数量。利用主动学习的机器学习技术能加快模型训练的进度和减少数据获取的资金投入。依靠主动学习来得到有价值的数据&#xff0c;以便机器模型从中学习。如果一个模型被具有价值的数据加以训练&#xff0c;它将以较少的人工标注和更短…

istio 示例程序 bookinfo 快速部署

官网 文档位置 相关 yaml 资源下载 Bookinfo 应用分为四个单独的微服务&#xff1a; productpage&#xff1a;这个微服务会调用 details 和 reviews 两个微服务&#xff0c;用来生成页面details&#xff1a;这个微服务中包含了书籍的信息reviews&#xff1a;这个微服务中包含了…

【SpringCloud笔记】(11)消息驱动之Stream

Stream 技术背景 底层不同模块可能使用不同的消息中间件&#xff0c;这就导致技术的切换&#xff0c;微服务的维护及开发变得麻烦起来 概述 官网&#xff1a; https://spring.io/projects/spring-cloud-stream#overview https://cloud.spring.io/spring-cloud-static/spring…

springcloud微服务篇--6.网关Gateway

一、为什么需要网关&#xff1f; 网关功能&#xff1a; 身份认证和权限校验 服务路由、负载均衡 请求限流 在SpringCloud中网关的实现包括两种&#xff1a; gateway zuul Zuul是基于Servlet的实现&#xff0c;属于阻塞式编程。而SpringCloudGateway则是基于Spring5中提供的Web…

Java学习笔记(八)——面向对象编程(高级)

目录 一、类变量和类方法 &#xff08;一&#xff09;类变量/静态变量 类变量内存布局 类变量使用注意事项和细节 &#xff08;二&#xff09;类方法 类方法经典的使用场景 类方法使用注意事项和细节 二、理解main方法语法 三、代码块 代码块使用注意事项和细节 四、…

FQML_AXI_GPIO工程构建调试记录

FQML_AXI_GPIO工程构建调试记录 一、概述 此记录JFMQL15T开发板&#xff0c;实现ps通过axi接口控制pl 的EMIO接口led闪烁&#xff0c;添加EMIO PJTAG用于PS端调试&#xff0c;先创建vivado工程&#xff0c;最终生成bitstream&#xff0c;procise从vivado中导入工程&#xff0…

深度学习 | 基本循环神经网络

1、序列建模 1.1、序列数据 序列数据 —— 时间 不同时间上收集到的数据&#xff0c;描述现象随时间变化的情况。 序列数据 —— 文本 由一串有序的文本组成的序列&#xff0c;需要进行分词。 序列数据 —— 图像 有序图像组成的序列&#xff0c;后一帧图像可能会受前一帧的影响…

GA/T1400公安视图库在视频监控系统中对接及方案

公安视频图像信息应用系统系列标准&#xff0c;标号为GA/T 1400&#xff0c;现行版本为2017年版&#xff0c;由公安部发布。现较广泛地使用于平安城市安防监控系统、智慧城市安防监控系统、雪亮工程安防监控系统之中。 公安视频图像信息应用系统系列标准&#xff0c;共分为4个部…

java美容管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 java Web美容管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0&…

电路设计(8)——计时器的multism仿真

1.功能设计 这是一个计时电路&#xff0c;在秒脉冲的驱动下&#xff0c;计时器开始累加&#xff0c;6个数码管分别显示计时的 时&#xff1a;分&#xff1a;秒。 仿真图如下所示&#xff1a; 左边的运放构成了振荡电路&#xff0c;可以产生脉冲波。这个脉冲波给计时电路提供基准…

金蝶云星空 多处反序列化RCE漏洞复现

0x01 产品简介 金蝶云星空是一款云端企业资源管理(ERP)软件,为企业提供财务管理、供应链管理以及业务流程管理等一体化解决方案。金蝶云星空聚焦多组织,多利润中心的大中型企业,以 “开放、标准、社交”三大特性为数字经济时代的企业提供开放的 ERP 云平台。服务涵盖:财…

关于“Python”的核心知识点整理大全44

目录 ​编辑 15.3.4 模拟多次随机漫步 rw_visual.py 注意 15.3.5 设置随机漫步图的样式 15.3.6 给点着色 rw_visual.py 15.3.7 重新绘制起点和终点 rw_visual.py 15.3.8 隐藏坐标轴 rw_visual.py 15.3.9 增加点数 rw_visual.py 15.3.10 调整尺寸以适合屏幕 rw_vi…

【Linux】生产者消费者模型(阻塞队列与环形队列)和POSIX信号量

文章目录 一、生产者消费者模型二、基于BlockingQueue的生产者消费者模型1.BlockQueue.hpp2.Task.hpp3.main.cc 三、POSIX信号量四、基于环形队列的生产消费模型1.RingQueue.hpp2.Task.hpp3.main.cc 一、生产者消费者模型 我们这里举一个例子&#xff0c;来解释生产者消费者模…

数据库的系统概述1

1.1 信息&#xff0c;数据&#xff0c;数据处理与数据管理 数据&#xff1a; 数据是描述事务的符号记录 信息&#xff1a; 信息是一种已经被加工为特定形式的数据&#xff0c;这种数据对接受者来说 是有意义的 数据管理&#xff1a; 利用计算机对收集的数据进行整理&#xff0…