百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

Qt—初识委托

bigegpt 2024-08-06 11:52 2 浏览

1 简介

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

委托可以做以下事情:

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

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

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

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

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

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

文章转自博客园(m晴朗):https://www.cnblogs.com/mqinglang/p/17076488.html

Qt开发必备技术栈学习路线和资料

相关推荐

Linux 系统启动完整流程

一、启动系统流程简介如上图,简述系统启动的大概流程:1:硬件引导UEFi或BIOS初始化,运行POST开机自检2:grub2引导阶段系统固件会从MBR中读取启动加载器,然后将控制权交给启动加载器GRU...

超专业解析!10分钟带你搞懂Linux中直接I/O原理

我们先看一张图:这张图大体上描述了Linux系统上,应用程序对磁盘上的文件进行读写时,从上到下经历了哪些事情。这篇文章就以这张图为基础,介绍Linux在I/O上做了哪些事情。文件系统什么是...

linux入门系列12--磁盘管理之分区、格式化与挂载

前面系列文章讲解了VI编辑器、常用命令、防火墙及网络服务管理,本篇将讲解磁盘管理相关知识。本文将会介绍大量的Linux命令,其中有一部分在“linux入门系列5--新手必会的linux命令”一文中已经...

Linux环境下如何设置多个交叉编译工具链?

常见的Linux操作系统都可以通过包管理器安装交叉编译工具链,比如Ubuntu环境下使用如下命令安装gcc交叉编译器:sudoapt-getinstallgcc-arm-linux-gnueab...

可算是有文章,把Linux零拷贝技术讲透彻了

阅读本文大概需要6.0分钟。作者:卡巴拉的树链接:https://dwz.cn/BaQWWtmh本文探讨Linux中主要的几种零拷贝技术以及零拷贝技术适用的场景。为了迅速建立起零拷贝的概念...

linux软链接的创建、删除和更新

大家都知道,有的时候,我们为了省下空间,都会使用链接的方式来进行引用操作。同样的,在系统级别也有。在Windows系列中,我们称其为快捷方式,在Linux中我们称其为链接(基本上都差不多了,其中可能...

Linux 中最容易被黑客动手脚的关键目录

在Linux系统中,黑客攻击后常会针对关键目录和文件进行修改以实现持久化、提权或隐藏恶意活动。本文介绍下黑客最常修改的目录及其手法。一、/etc目录关键文件有:/etc/passwd和/et...

linux之间传文件命令之Rsync傻瓜式教程

1.前言linux之间传文件命令用什么命令?本文介绍一种最常用,也是功能强大的文件同步和传输工具Rsync,本文提供详细傻瓜式教程。在本教程中,我们将通过实际使用案例和最常见的rsync选项的详细说...

Linux下删除目录符号链接的方法

技术背景在Linux系统中,符号链接(symlink)是一种特殊的文件,它指向另一个文件或目录。有时候,我们可能需要删除符号链接,但保留其指向的目标目录。然而,在删除符号链接时可能会遇到一些问题,例如...

阿里云国际站注册教程:aa云服务器怎么远程链接?

在全球化的今天,互联网带给我们无以计数的便利,而云服务器则是其中的重要基础设施之一。这篇文章将围绕阿里云国际站注册、aa云服务器如何远程链接,以及服务器安全防护如Ddos防火墙、网站应用防护waf防火...

Linux 5.16 网络子系统大范围升级 多个新适配器驱动加入

Linux在数据中心中占主导地位,因此每个内核升级周期的网络子系统变化仍然相当活跃。Linux5.16也不例外,周一最新与网络相关的更新加入了大量的驱动和新规范的支持。一个较新硬件的驱动是Realt...

搭建局域网文件共享服务(Samba),手机电脑都能看喜欢的影视剧

作为一名影视爱好者,为了方便地观看自己喜欢的影视作品,在家里搞一个专门用来存放电影的服务器是有必要的。蚁哥选则用一台Ubuntu系统的电脑做为服务器,共享影音文件,其他同一个局域网内的电脑或手机可以...

分享一个实用脚本—centos7系统巡检

概述这周闲得慌,就根据需求写了差不多20个脚本(部分是之前分享过的做了一些改进),今天主要分享一个给平时运维人员用的centos7系统巡检的脚本,或者排查问题检查系统情况也可以用..实用脚本#!/bi...

Linux 中创建符号链接的方法

技术背景在Linux系统里,符号链接(SymbolicLink),也被叫做软链接(SoftLink),是一种特殊的文件,它指向另一个文件或者目录。符号链接为文件和目录的管理带来了极大的便利,比...

一文掌握 Linux 符号链接

符号链接(SymbolicLink),通常被称为“软链接”,是Linux文件系统中一种强大而灵活的工具。它允许用户创建指向文件或目录的“快捷方式”,不仅简化了文件管理,还在系统配置、软件开发和日...