C++ Qt开发:QItemDelegate 自定义代理组件
Qt 是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍QStyledItemDelegate
自定义代理组件的常用方法及灵活运用。
在Qt中,QStyledItemDelegate
类是用于创建自定义表格视图(如QTableView
和QTableWidget
)的委托类,允许你自定义表格中每个单元格的外观和交互。QStyledItemDelegate
是QItemDelegate
的子类,提供了更现代、更易用的接口。此处我们将实现对QTableView
表格组件的自定义代理功能,例如默认情况下表格中的缺省代理就是一个编辑框,我们只能够在编辑框内输入数据,而有时我们想选择数据而不是输入,此时就需要重写编辑框实现选择的效果,代理组件常用于个性化定制表格中的字段类型。
1.1 概述代理类
代理类的作用是用来实现组件重写的,例如TableView
中默认是可编辑的,之所以可编辑是因为Qt默认为我们重写了QLineEdit
编辑框实现的,也可理解为将组件嵌入到了表格中,实现了对表格的编辑功能。
在自定义代理中QAbstractItemDelegate
是所有代理类的抽象基类,它用于创建自定义的项委托。提供了一个基本的框架,使得可以定制如何在视图中绘制和编辑数据项。
QAbstractItemDelegate
是 QItemDelegate
的基类,而 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
组件,这有助于让用户直接选择一个状态,如下图;
C++ Qt开发:QItemDelegate 自定义代理组件的更多相关文章
- C/C++ Qt TableDelegate 自定义代理组件
TableDelegate 自定义代理组件的主要作用是对原有表格进行调整,例如默认情况下Table中的缺省代理就是一个编辑框,我们只能够在编辑框内输入数据,而有时我们想选择数据而不是输入,此时就需要重 ...
- 浅尝Spring注解开发_自定义注册组件、属性赋值、自动装配
Spring注解开发 浅尝Spring注解开发,基于Spring 4.3.12 包含自定义扫描组件.自定义导入组件.手动注册组件.自动注入方法和参数.使用Spring容器底层组件等 配置 @Confi ...
- iOS开发之自定义表情键盘(组件封装与自动布局)
下面的东西是编写自定义的表情键盘,话不多说,开门见山吧!下面主要用到的知识有MVC, iOS开发中的自动布局,自定义组件的封装与使用,Block回调,CoreData的使用.有的小伙伴可能会问写一个自 ...
- SSIS自定义数据流组件开发(血路)
由于特殊的原因(怎么特殊不解释),需要开发自定义数据流组件处理. 查了很多资料,用了不同的版本,发现各种各样的问题没有找到最终的解决方案. 遇到的问题如下: 用VS2015编译出来的插件,在SSDTB ...
- Android Studio开发基础之自定义View组件
一般情况下,不直接使用View和ViewGroup类,而是使用使用其子类.例如要显示一张图片可以用View类的子类ImageView,开发自定义View组件可分为两个主要步骤: 一.创建一个继承自an ...
- android开发之自定义组件
android开发之自定义组件 一:自定义组件: 我认为,自定义组件就是android给我们提供的的一个空白的可以编辑的图片,它帮助我们实现的我们想要的界面,也就是通过自定义组件我们可以把我们要登入的 ...
- Android开发——构建自定义组件
Android中,你的应用程序程序与View类组件有着一种固定的联系,例如按钮(Button). 文本框(TextView), 可编辑文本框(EditText), 列表框(ListView), 复选框 ...
- h5 录音 自动生成proto Js语句 UglifyJS-- 对你的js做了什么 【原码笔记】-- protobuf.js 与 Long.js 【微信开发】-- 发送模板消息 能编程与会编程 vue2入坑随记(二) -- 自定义动态组件 微信上传图片
得益于前辈的分享,做了一个h5录音的demo.效果图如下: 点击开始录音会先弹出确认框: 首次确认允许后,再次录音不需要再确认,但如果用户点击禁止,则无法录音: 点击发送 将录音内容发送到对话框中.点 ...
- QT使用提升自定义组件
QT使用提升自定义组件 QTC++QT自定义 QT 组件提升来实现自定义功能 介绍 我们在使用QT设置界面之后,往往需要自己实现一些方法,如果是单独 的还好,但是如果遇到很多同类型的都有需求, 比如 ...
- 【Android 应用开发】 自定义组件 宽高适配方法, 手势监听器操作组件, 回调接口维护策略, 绘制方法分析 -- 基于 WheelView 组件分析自定义组件
博客地址 : http://blog.csdn.net/shulianghan/article/details/41520569 代码下载 : -- GitHub : https://github.c ...
随机推荐
- 企业级低代码平台,通用代码生成平台,Java开源项目(附源码)
项目介绍 Jeecg-Boot 是一款基于代码生成器的智能开发平台!采用前后端分离架构:SpringBoot,Mybatis,Shiro,JWT,Vue&Ant Design.强大的代码生成器 ...
- 如何保持 SSH 会话不中断?
哈喽大家好,我是咸鱼 不知道小伙伴们有没有遇到过下面的情况: 使用终端(XShell.secureCRT 或 MobaXterm 等)登录 Linux 服务器之后如果有一段时间没有进行交互,SSH 会 ...
- 【题解】Educational Codeforces Round 141(CF1783)
评价:educational A.Make it Beautiful 题目描述: 如果一个数组中存在一个数恰好等于该数前面所有数之和,那么这个数组就是丑的.如果一个数组不是丑的,就是美的. 比如说: ...
- TOP GP 把已经编译的per反编回对应版本的4fd(画面档)
由于GP5.1,5.2,5.3的genero对应版本画面档开发互不兼容,下面提供各版本之间互转的操作方法: xshell切换到要反编译的per档目录,执行以下命令,就会在同目录下生成对应4fd档资料 ...
- ERROR: Command errored out with exit status 1:
Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple Collecting CairoSVG==2.4.2 Using cached ...
- 我试图扯掉这条 SQL 的底裤。
你好呀,我是歪歪. 这次带大家盘一个我觉得有点意思的东西,也是之前写<一个烂分页,踩了三个坑!>这篇文章时,遇到的一个神奇的现象,但是当时忙着做文章搞定这个主线任务,就没有去深究这个支线任 ...
- 实验四报告: 熟悉Python字典、集合、字符串的使用
实验目标 本实验的主要目标是熟悉Python中字典.集合.字符串的创建和操作,包括字典的创建.访问.修改和合并,集合的创建.访问以及各种集合运算,以及字符串的创建.格式化和常用操作. 实验要求 通过编 ...
- `.NET Web`新人入门必学项目`EarthChat`
.NET Web新人入门必学项目EarthChat EarthChat是一个基于.NET 7的实战项目,EarthChat提供了很多的最佳实践,EarthChat的目标也是成为一个很多人都喜欢的大型聊 ...
- QGradient渐变填充
QGradient渐变填充 QGradient (一)简介 (二)枚举类型 1.spread 2.CoordinateMode 3.type (三)常用函数 1.coordinateMode() 2. ...
- shell解析xml文档
需要解析的源文件: /tmp/cameralist : <?xml version="1.0" encoding="UTF-8"?><came ...