QT(7)-初识委托

news2024/11/15 20:39:38

初识委托

  • 1 简介
  • 2 QT中的委托类
    • 2.1 函数
      • 2.1.1 关键函数
      • 2.1.2 其他函数
  • 3 例子
    • 3.1 官方例子
    • 3.2 修改官方例子
  • 4 设想

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,然后将常用的委托全部实现,然后创建一些接口,通过这些接口对编辑器进行选择和初始化。肯定是可以的,那就期待一些吧!

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

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

相关文章

天空卫士参与编写的《数据安全治理实践指南(2.0)》正式发布

2023年1月5日&#xff0c;由中国信息通信研究院&#xff08;以下简称“中国信通院”&#xff09;、中国通信标准化协会指导&#xff0c;中国通信标准化协会大数据技术标准推进委员会主办&#xff0c;数据安全推进计划承办的第二届数据安全治理峰会在北京召开。本次峰会发布多项…

算法刷题打卡第64天:平衡二叉树

平衡二叉树 难度&#xff1a;简单 给定一个二叉树&#xff0c;判断它是否是高度平衡的二叉树。 本题中&#xff0c;一棵高度平衡二叉树定义为&#xff1a; 一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。 示例 1&#xff1a; 输入&#xff1a;root [3,9,…

错误票据(第四届蓝桥杯省赛C++A/B组,第四届蓝桥杯省赛JAVAA/B组)

题目详细&#xff1a;解题思路&#xff1a;这题的难点主要在于对于数据的读入以及对于两个数字的查找对于数据的读入&#xff1a;1.直接对单行字符串进行转换&#xff1a;题目所给出的输入只有行数并不知道一行有多少个数字所以我们采用一下读取一行然后对一行的结果进行读入首…

docker提交腾讯云标准模式

简介我们公司的容器化标准模式&#xff0c;本次是以redis为例进行示范技术要求:你会简单的docker容器打包环境需要:docker、docker-compose、联网环境、腾讯云容器及镜像服务&#xff08;公司已有TKE&#xff09;文件需要&#xff1a;除了你自己的Dockerfile所需要的东西外&…

TensorFlow 基础(三)梯度和自动微分

文章目录Computing gradientsGradient tapesGradients with respect to a modelControlling what the tape watchesIntermediate resultsGradients of non-scalar targetsCases where gradients returns NoneReferencesimport numpy as np import matplotlib.pyplot as pltimpo…

【自学Python】Python三目运算符

Python三目运算符 Python三目运算符教程 Python 中没有其他语言类型的三目运算符&#xff0c;但是我们可以借助 if 语句实现类似的三目运算符。 Python三目运算符详解 说明 Python 的三目运算符是借助于 if 语句来实现的。 语法 True_statements if condition else Fals…

千锋教育嵌入式物联网教程之系统编程篇学习-02

目录 系统调用函数与库函数 库函数的组成 库函数与系统调用的关系 进程概述 进程的定义 进程与程序的区别 进程的状态及其转换 进程的调度机制 进程控制块 查看当前系统所有进程 进程号函数 进程创建fork函数 进程挂起 进程的等待 wait() waitpid 特殊进程 …

CPU 运行时的硬件环境详解

注&#xff1a;本文参考小林coding相关文章&#xff0c;侵权请联系 目录 1.图灵机的工作方式 2.冯诺依曼模型 3.内存 4.中央处理器 5总线 6.输入、输出设备 7.线路位宽与 CPU 位宽 代码写了那么多&#xff0c;你知道 a 1 2 这条代码是怎么被 CPU 执行的吗&#xff1f; …

TCP/IP协议族之TCP、UDP协议详解(小白也能看懂)

前言 在进行网络编程之前&#xff0c;我们必须要对网络通信的基础知识有个大概的框架&#xff0c;TCP/IP协议族涉及到多种网络协议&#xff0c;一般说TCP/IP协议&#xff0c;它不是指某一个具体的网络协议&#xff0c;而是一个协议族。本篇章主要针对IP协议、TCP和UDP协议记录总…

常用的代码命名方法

常见的三种命名方法1 驼峰命名法&#xff08;CamelCase&#xff09;驼峰命名法应该我们最常见的一个&#xff0c;这种命名方式使用大小写混合的格式来区别各个单词&#xff0c;并且单词之间不使用空格隔开或者连接字符连接的命名方式1 大驼峰命名法&#xff08;UpperCamelCase&…

Mysql 基础-持续更新

去重 DISTINCT DISTINCT 关键字的主要作用就是对数据表中一个或多个字段重复的数据进行过滤&#xff0c;只返回其中的一条数据给用户 注意点&#xff1a; DISTINCT 关键字只能在 SELECT 语句中使用。在对一个或多个字段去重时&#xff0c;DISTINCT 关键字必须在所有字段的最前…

IPv6路由协议实验配置(ospfv3、isis-ipv6、bgp4+)

目录 OSPFv3实验配置 建立OSPFv3邻居 AR1修改DR优先级 AR1引入直连路由 配置Stub区域 ISIS IPv6实验配置 建立ISIS邻居 修改AR1的DIS优先级 在AR1上配置路由泄露 BGP4实验配置 AR1与AR2、AR3建立IBGP邻居关系 AR2与AR4建立EBGP邻居关系 配置AR1为反射器 OSPFv3实验…

Android时间与服务器同步方案

转自&#xff1a; https://blog.csdn.net/qinci/article/details/70666631这个的吧&#xff1f;转发请注明来源吧&#xff1f;Android时间与服务器同步方法_飛舞的青春的博客-CSDN博客Android时间与服务器同步方案 在部分软件应用场景里&#xff0c;我们对应用时间要求非常苛刻…

mysql navicat函数_Navicat for MySQL函数高级属性

过程和函数是一组可以保存在服务器上的SQL语句。MySQL(www.formysql.com)函数高级属性主要涉及安全性&#xff0c;定义者&#xff0c;数据访问&#xff0c;决定性等方面的内容Navicat 函数高级属性安全性&#xff1a;指定用创建函数的用户权限来运行函数&#xff0c;或是用启用…

【C++】vector (vector的介绍及使用)

文章目录vector的介绍及使用前面我们学习了string&#xff0c;我们在学vector可以结合之前的理解&#xff0c;所以我们vector就不详细介绍了。 vector的介绍及使用 vector是表示可变大小数组的序列容器。就像数组一样&#xff0c;vector也采用的连续存储空间来存储元素。也就…

一个没有混进大厂的普通程序员,10年真实收入变化

有人说&#xff0c;程序员的高收入和工作年限成正比&#xff0c;认为自己的薪资应该如此计算&#xff1a; private static boolean 计算工资() { //years工作时长(年)int years 5;while(years-- > 0){做项目();团建活动();涨工资();拿年终奖();}return 跳槽() &&…

2021年亚太杯APMCM数学建模大赛A题图像边缘分析与应用求解全过程文档及程序

2021年亚太杯APMCM数学建模大赛 A题 图像边缘分析与应用 原题再现&#xff1a; 随着科学技术的发展&#xff0c;对各种工件和零部件测量精度的要求越来越高&#xff0c;对测量仪器的要求也越来越高。数字图像尺寸测量仪器等各种图像测量设备目前正逐渐取代传统的手动卡尺测量…

Vue 常用内置指令

Vue 常用内置指令描述指令内容渲染指令{{}} 与 v-text覆盖面积v-text{{}}闪现问题{{}}v-textv-html属性绑定指令v-bind简写 :事件绑定指令v-on参数事件对象$event事件修饰符按键修饰符双向绑定指令v-model修饰符条件渲染指令v-show 与 v-if 的区别实现原理性能消耗举个栗子v-el…

C#构建Web服务项目实战(二)

概述本文演示了如何通过Ajax访问C# ASP.NET项目中的WebService方法&#xff08;.asmx文件形式&#xff09;。本文的项目配置参见前文&#xff1a;C#构建Web服务项目实战&#xff08;一&#xff09;。环境Visual Studio 2017 / VS2019C# ASP.NET Web服务Win11 / Win10类似.NET F…

由浅入深地学习指针(学习指针必看)

目录 指针初阶 指针定义 指针和指针类型 c语言的整型指针解引用与整型变量的区别 内存 指针和指针类型 指针类型的意义 野指针 规避野指针 指针运算 指针和数组 二级指针 指针数组 指针进阶 指针的概念再提起 字符指针 《剑指offer》 字符串常量&#xff1a; …