@

1 简介

委托是Qt中的一种机制,用于在Qt模型/视图架构中处理特定类型的数据。委托提供了一种方便的方法来定制特定类型的数据的显示和编辑。

委托可以做以下事情:

  • 编辑特定类型的数据: 通过创建编辑器来编辑特定类型的数据,例如日期,数值等.
  • 渲染特定类型的数据: 通过定制单元格的外观来渲染特定类型的数据,例如颜色,字体等.
  • 支持不同类型的编辑器: 支持不同类型的编辑器,例如文本编辑器,下拉列表编辑器等.
  • 处理编辑器的事件: 通过实现eventFilter()方法来处理编辑器的事件,如键盘事件.
  • 更新编辑器的尺寸: 通过实现sizeHint()方法来更新编辑器的尺寸.
  • 数据验证: 通过实现editorEvent()来验证编辑器中的数据是否合法。

委托的常见应用场景包括:

  • 表格和列表视图: 在表格和列表视图中使用委托可以方便地编辑单元格中的数据,并定制单元格的外观.
  • 属性编辑器: 使用委托可以创建自定义属性编辑器来编辑特定类型的属性.
  • 文件对话框: 使用委托可以定制文件对话框中的文件列表的外观.

model view delegate(MVD):

由于模型负责组织数据,而视图负责显示数据,所以当用户想修改显示的数据时,就要通过视图中的委托来完成

总之,委托可以用来定制Qt中各种视图组件中特定类型的数据的显示和编辑,使得开发人员能够更好地控制数据的外观和行为。使用委托可以使代码更具可重用性和灵活性

2 QT中的委托类

QAbstractItemDelegate是Qt中一个抽象基类,它提供了委托类的基本功能。它是Qt中所有委托类的基类。

QItemDelegate是QAbstractItemDelegate的子类,它提供了一种通用的委托类,可以用于编辑和渲染大多数类型的数据。它提供了默认的编辑器,如QLineEdit和QSpinBox,用于编辑数值和字符串类型的数据。

QStyledItemDelegate是QItemDelegate的子类,它使用Qt Style Sheets来渲染单元格中的数据,这样可以更好地与应用程序的外观保持一致。它还提供了一些额外的功能,如支持自定义编辑器和支持编辑器工厂,这样可以更好地管理编辑器。

2.1 函数

2.1.1 关键函数

virtual QWidget * createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const

它用于创建用于编辑特定单元格中数据的编辑器。

该函数需要三个参数:

  • parent: 编辑器的父窗口,通常为表格视图。
  • option: 包含编辑器相关信息的QStyleOptionViewItem对象。
  • index: 包含需要编辑的数据的QModelIndex对象。

该函数返回一个指向创建的编辑器的指针。

virtual void setEditorData(QWidget *editor, const QModelIndex &index) const

它用于将数据模型中的数据设置到编辑器中。这个函数在编辑器被创建后被调用,用于初始化编辑器的值。

它接受两个参数:

  • editor: 编辑器的指针。
  • index: 模型索引,表示编辑器要编辑的数据在数据模型中的位置。

virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const

它用于将编辑器中的数据保存到数据模型中。这个函数在编辑器编辑完成后被调用,用于更新数据模型中的数据。

它接受三个参数:

  • editor: 编辑器的指针。
  • model: 数据模型的指针。
  • index: 模型索引,表示编辑器要编辑的数据在数据模型中的位置。

virtual void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const

它用于更新编辑器的位置和大小。这个函数在编辑器被创建后被调用,用于设置编辑器的位置和大小。

它接受三个参数:

  • editor: 编辑器的指针。
  • option: QStyleOptionViewItem类型的对象,表示编辑器的显示选项。
  • index: 模型索引,表示编辑器要编辑的数据在数据模型中的位置。

一般通过继承 QStyledItemDelegate以上4个函数,便可以实现简单的自定义委托。

virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const = 0

它用于在视图中渲染单元格中的数据。这个函数被调用来绘制一个单元格中的数据,并且它是一个纯虚函数,需要在子类中重写。

它接受三个参数:

  • painter: QPainter的指针。
  • option: QStyleOptionViewItem类型的对象,表示编辑器的显示选项。
  • index: 模型索引,表示要绘制的数据在数据模型中的位置。

2.1.2 其他函数

virtual void destroyEditor(QWidget *editor, const QModelIndex &index) const

它用于在编辑器关闭时销毁编辑器。这个函数在编辑器关闭时被调用,用于释放编辑器占用的资源。

它接受两个参数:

  • editor: 编辑器的指针。
  • index: 模型索引,表示编辑器要编辑的数据在数据模型中的位置。

virtual bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)

它用于处理来自编辑器的事件。这个函数在编辑器上发生事件时被调用,用于处理编辑器上的事件。

它接受四个参数:

  • event: QEvent类型的对象,表示发生的事件。
  • model: 数据模型的指针。
  • option: QStyleOptionViewItem类型的对象,表示编辑器的显示选项。
  • index: 模型索引,表示编辑器要编辑的数据在数据模型中的位置。

virtual bool helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &index)

virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const = 0

总之,这些函数并没有重要和非重要之分,需要根据不同的需求实现不同的函数,达到想要的效果。

3 例子

3.1 官方例子

官方例子在\Qt5.x.x\Examples\Qt-5.12.9\widgets\itemviews\spinboxdelegate

实现自定义数值输入

delegate.h

#ifndef DELEGATE_H
#define DELEGATE_H #include <QStyledItemDelegate> //! [0]
class SpinBoxDelegate : public QStyledItemDelegate
{
Q_OBJECT public:
SpinBoxDelegate(QObject *parent = nullptr); QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
const QModelIndex &index) const override; void setEditorData(QWidget *editor, const QModelIndex &index) const override;
void setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const override; void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,
const QModelIndex &index) const override;
};
//! [0] #endif

delegate.cpp

#include "delegate.h"

#include <QSpinBox>

//! [0]
SpinBoxDelegate::SpinBoxDelegate(QObject *parent)
: QStyledItemDelegate(parent)
{
}
//! [0] //! [1]
QWidget *SpinBoxDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &/* option */,
const QModelIndex &/* index */) const
{
QSpinBox *editor = new QSpinBox(parent);
editor->setFrame(false);
editor->setMinimum(0);
editor->setMaximum(100); return editor;
}
//! [1] //! [2]
void SpinBoxDelegate::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);
}
//! [2] //! [3]
void SpinBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const
{
QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
spinBox->interpretText();
int value = spinBox->value(); model->setData(index, value, Qt::EditRole);
}
//! [3] //! [4]
void SpinBoxDelegate::updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option,
const QModelIndex &/* index */) const
{
editor->setGeometry(option.rect);
}
//! [4]

main

#include "delegate.h"

#include <QApplication>
#include <QHeaderView>
#include <QStandardItemModel>
#include <QTableView> //! [0]
int main(int argc, char *argv[])
{
QApplication app(argc, argv); QStandardItemModel model(4, 2);
QTableView tableView;
tableView.setModel(&model); SpinBoxDelegate delegate;
tableView.setItemDelegate(&delegate);
//! [0] tableView.horizontalHeader()->setStretchLastSection(true); //! [1]
for (int row = 0; row < 4; ++row) {
for (int column = 0; column < 2; ++column) {
QModelIndex index = model.index(row, column, QModelIndex());
model.setData(index, QVariant((row + 1) * (column + 1)));
}
//! [1] //! [2]
}
//! [2] //! [3]
tableView.setWindowTitle(QObject::tr("Spin Box Delegate"));
tableView.show();
return app.exec();
}

在createEditor函数中,定义了一个 QSpinBox类型的编辑器,并对其进行了简单的初始化和设置

在setEditorData函数中,将模型中index位置的数据拿了出来并保存在了value中,并将value设置到了编辑器中

在setModelData函数中,将编辑器中的数据取出来设置到了模型中

在updateEditorGeometry中,对位置进行了设置,editor->setGeometry(option.rect);(不执行这个生成的控件在坐标原点 )

3.2 修改官方例子

那么我们照葫芦画瓢,修改一下上面函数里的内容,看看能不能实现其他的委托

delegate.cpp

#include "delegate.h"

#include <QSpinBox>
#include <QDateEdit>
//! [0]
SpinBoxDelegate::SpinBoxDelegate(QObject *parent)
: QStyledItemDelegate(parent)
{
}
//! [0] //! [1]
QWidget *SpinBoxDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &/* option */,
const QModelIndex &/* index */) const
{
// QSpinBox *editor = new QSpinBox(parent);
// editor->setFrame(false);
// editor->setMinimum(0);
// editor->setMaximum(100); auto *editor = new QDateEdit(parent);
editor->setDisplayFormat("yyyy-MM-dd"); return editor;
}
//! [1] //! [2]
void SpinBoxDelegate::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); auto value = index.model()->data(index, Qt::EditRole).toDate();
QDateEdit *dateEdit = static_cast<QDateEdit*>(editor);
dateEdit->setDate(value);
}
//! [2] //! [3]
void SpinBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const
{
// QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
// spinBox->interpretText();
// int value = spinBox->value(); // model->setData(index, value, Qt::EditRole); auto dateEdit = static_cast<QDateEdit*>(editor);
auto value = dateEdit->date();
model->setData(index,value,Qt::EditRole);
}
//! [3] //! [4]
void SpinBoxDelegate::updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option,
const QModelIndex &/* index */) const
{
editor->setGeometry(option.rect);
}
//! [4]

我创建了一个QDateEdit类型的编辑器,并按照之前的思路,进行了函数的重新实现。运行效果如下:

看到这里,相信你已经对委托有了初步的认识。

4 设想

通过上面的列子,你或许发现了如果按照这个思路,那么只要改一下里面的编辑器,就能实现不同的委托。确实如此,虽然上面的例子很简单,但是给我们提供了思路,想要实现不同的委托,只要继承QStyledItemDelegate类,并实现相应的函数,就可以实现不同的委托。

假设一个项目需要,密码委托,下拉框委托(QComboBox),颜色选择委托,图标委托等等,甚至包括一些,你自己定义的控件的委托。那么我们每实现一个委托,就要单独继承一次QStyledItemDelegate类吗?当然这也可以,但是不觉得总有些怪怪的吗?

有没有这样一种可能,我们创建一个类,并继承QStyledItemDelegate,然后将常用的委托全部实现,然后创建一些接口,通过这些接口对编辑器进行选择和初始化。肯定是可以的,那就期待一些吧!

QT(7)-初识委托的更多相关文章

  1. Qt 模型/视图/委托

    模型.视图.委托 模型/视图架构基于MVC设计模式发展而来.MVC中,模型(Model)用来表示数据:视图(View)是界面,用来显示数据:控制(Controller)定义界面对用户输入的反应方式. ...

  2. C#委托学习

    标签(空格分隔): C# 看Markdown效果支持的不大好. 买来<CLR Via C#>这本书很久了,一直也没有对其进行总结,看的非常凌乱,趁此机会好好总结一下,也算对C#学习的一个总 ...

  3. [CLR via C#]17. 委托

        回调函数是一种非常有用的编程机制,它已经存在很多年了.Microsoft .NET Framework通过委托(delegate)来提供一种回调机制.不同于其他平台(比如非托管C++)的回调机 ...

  4. CLR之委托的揭秘(一)

    初识委托:          在之前的学习中我们已经可以把对象,值,数组当作参数传递给方法,但是有没有可能把方法也当作参数传递给方法呢?有了这个想法于是就有了委托.方法当作一种参数去传递,但是方法有的 ...

  5. 【C#复习总结】细说委托

    1 前言 本系列会将[委托] [匿名方法][Lambda表达式] [泛型委托] [表达式树] [事件]等基础知识总结一下.(本人小白一枚,有错误的地方希望大佬指正) 系类1:细说委托 系类2:细说匿名 ...

  6. <NET CLR via c# 第4版>笔记 第17章 委托

    17.1 初识委托 .net 通过委托来提供回调函数机制. 委托确保回调方法是类型安全的. 委托允许顺序调用多个方法. 17.2 用委托回调静态方法 将方法绑定到委托时,C# 和 CLR 都允许引用类 ...

  7. (一) Qt Model/View 的简单说明

    (一) Qt Model/View 的简单说明 .预定义模型 (二)使用预定义模型 QstringListModel例子 (三)使用预定义模型QDirModel的例子 (四)Qt实现自定义模型基于QA ...

  8. 重温CLR(十二) 委托

    回调函数是一种非常有用的编程机制,它的存在已经有很多年了..NET通过委托来提供回调函数机制.不同于其他平台(比如非托管C++)的回调机制,委托的功能要多得多.例如,委托确保回调方法是类型安全的(这是 ...

  9. QT界面 理解QStyle和QStyleOption以及QStyleFactory

    QStyleOption类和QStyle类简介 QStyleOption类存储QStyle函数使用的参数.QStyleOption及其子类包含了QStyle函数绘制图形元素所需的所有信息. 由于性能原 ...

  10. Qt 学习之路 2(50):自定义可编辑模型

    Home / Qt 学习之路 2 / Qt 学习之路 2(50):自定义可编辑模型 Qt 学习之路 2(50):自定义可编辑模型 豆子 2013年5月13日 Qt 学习之路 2 13条评论 上一章我们 ...

随机推荐

  1. 【技术积累】JavaScript中的基础语法【二】

    JavaScript编写方式 JavaScript是一种脚本语言,用于为网页添加交互性和动态功能.它可以直接嵌入到HTML中,并通过浏览器解释执行.下面是一些常见的JavaScript编写方式和相应的 ...

  2. test.sh

    #!/bin/bash echo "=== show OS version ===" cat /etc/os-release echo "=== show IP addr ...

  3. Python数据可视化-折线图

    Python数据可视化-折线图 一.JSON数据格式 1.1 什么是json JSON是一种轻量级的数据交互格式.可以按照JSON指定的格式去组织和封装数据 JSON本质上是一个带有特定格式的字符串 ...

  4. pycharm链接mysql报错: Server returns invalid timezone. Go to 'Advanced' tab and set 'serverTimezone' property manually.

    检查驱动 我本机安装的mysql版本是5.6的,那么IDEA要连接mysql也应该匹配下驱动版本.把Driver改成MySQL for 5.1就可以了. 参考链接:https://blog.csdn. ...

  5. ABC274 题解

    A 题目:给定 \(A,B\) 输出 \({B}\over{A}\) 保留 \(3\) 位小数. 简答题,和A+B problem 一样,除一除,保留一下小数. B 题目:给定一个 \(n\) 行 \ ...

  6. 预处理器 Less 的十个语法

    Less 是一门 CSS 预处理语言,它扩充了 CSS 语言,增加了诸如变量.混合(mixin).函数等功能,让 CSS 更易维护.方便制作主题.扩充. 不过浏览器只能识别 CSS 语言,所以 Les ...

  7. JS逆向实战21——某查查webpack密码加密

    声明 本文章中所有内容仅供学习交流,抓包内容.敏感网址.数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除! 网站 aHR0cHM6Ly ...

  8. 《Web安全基础》02. 信息收集

    @ 目录 1:CDN 绕过 1.1:判断是否有 CDN 服务 1.2:常见绕过方法 1.3:相关资源 2:网站架构 3:WAF 4:APP 及其他资产 5:资产监控 本系列侧重方法论,各工具只是实现目 ...

  9. 京东工业根据ID取商品详情 API

    item_get-根据ID取商品详情  注册开通 vipmro.item_get 公共参数 名称 类型 必须 描述 key String 是 调用key(必须以GET方式拼接在URL中) secret ...

  10. gitlab与LDAP 联调

    gitlab整理 目录 gitlab整理 1.安装Gitlab依赖包 2.下载,安装 3.配置,访问域名及邮箱 4.初始化,启动 5.访问,以及邮箱测试 5.1汉化 6.问题总结处理 6.1安装时出现 ...