在上一章学习 25.QT-模型视图 后,本章接着学习视图委托


视图委托(Delegate)简介

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

视图委托类似于传统的MVC设计模式里的Controller(控制器)角色

  • Model(模型) - 负责数据组织
  • View(视图) - 负责数据显示
  • Controller(控制器) - 负责用户输入,并处理数据

初探自定义委托类 

  • 委托属于视图的子功能
  • 视图主要负责组织具体数据项的显示方式(是列表方式,还是树形方式,还是表格方式)
  • 委托主要负责具体数据项的显示和编辑,比如用户需要编辑某个数据时,则需要弹出编辑框
  • 视图可以通过 itemDelegate() ,setItemDelegate ( )成员函数来 获得/设置当前委托对象
  • QAbstractItemDelegate类是所有委托的父类,用来 负责提供通用接口
  • 在模型视图中,会默认提供一个QStyledItemDelegate类,供用户编辑数据
  • 也可以通过继承QItemDelegate父类,实现自定义委托功能

QAbstractItemDelegate类中的关键虚函数

QWidget * createEditor( QWidget * parent, QStyleOptionViewItem & option, QModelIndex & index ) ;
//创建编辑器,并返回该编辑器, option包含了该数据项的具体信息(比如:数据项窗口大小,字体格式,对齐方式,图标位于字体的哪个位置等)、index 包含了该数据项的内容(比如:text信息,背景色等) void updateEditorGeometry ( QWidget * editor, QStyleOptionViewItem & option, QModelIndex &index );
//该函数里,可以通过editor->setGeometry()更新编辑组件大小,保证editor显示的位置及大小
//大小可以通过option.rect获取数据项窗口大小 void setEditorData ( QWidget * editor, const QModelIndex & index );
//通过索引值,将模型里的数据提取到编辑器内容里 void setModelData ( QWidget * editor, QAbstractItemModel * model, QModelIndex & index );
//通过索引值, 根据editor 的数据更新model的数据。 void paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) ;
//复制绘画数据项的显示和编辑

QAbstractItemDelegate类中的关键信号

void  closeEditor ( QWidget * editor, QAbstractItemDelegate::EndEditHint hint = NoHint );
//当用户关闭编辑器后,就会发出这个信号。
// hint 参数用来指定当用户完成编辑后,应该显示什么标记,用来提示用户已完成编辑 void commitData ( QWidget * editor ) ;
//当完成编辑数据后,发送该信号,表示有新数据提交到模型中

我们以编辑某个数据项为例:

  • 视图首先会调用createEditor()函数生成编辑器
  • 调用updateEditorGeometry()函数设置编辑器组件大小
  • 调用setEditorData()函数,将模型里的数据提取到编辑器中
  • 等待用户编辑... ...
  • 当用户编辑完成后, 系统将会发送commitData信号函数
  • 然后调用setModelData()函数,设置模型数据,以及setEditorData()函数,更新编辑器
  • 视图最后发送closeEditor()信号函数,表示已关闭编辑器

接下来,我们重写上面函数,来自定义一个QCostomizedDelegate委托类

效果如下

QCustomizedDelegate.h:

#ifndef QCUSTOMIZEDDELEGATE_H

#define QCUSTOMIZEDDELEGATE_H

#include <QItemDelegate>

#include <QtGui>

class QCustomizedDelegate : public QItemDelegate

{

    Q_OBJECT

public:

    explicit QCustomizedDelegate(QObject *parent = );

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

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

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

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

};

#endif // QCUSTOMIZEDDELEGATE_H

QCustomizedDelegate.cpp:

#include "QCustomizedDelegate.h"
QCustomizedDelegate::QCustomizedDelegate(QObject *parent) :
QItemDelegate(parent)
{
} QWidget* QCustomizedDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if(index.column()==) //第1列 班级
{
QComboBox *Cbox = new QComboBox(parent);
Cbox->addItems(QStringList()<<"1班"<<"2班"<<"3班"<<"4班"<<"5班");
return Cbox;
}
else if(index.column()==) //第2列 分数
{
QSpinBox *Sbox = new QSpinBox(parent);
Sbox->setRange(,);
return Sbox;
} return QItemDelegate::createEditor(parent, option, index); //第0列,则选择默认编辑器
} void QCustomizedDelegate::setEditorData ( QWidget * editor, const QModelIndex & index ) const
{
if(index.column()==) //第1列 班级
{
QComboBox *Cbox = dynamic_cast<QComboBox*>(editor);
Cbox->setCurrentIndex(Cbox->findText( index.data(Qt::DisplayRole).toString()));
}
else if(index.column()==) //第2列 分数
{
QSpinBox *Sbox = dynamic_cast<QSpinBox*>(editor);
Sbox->setValue(index.data(Qt::DisplayRole).toInt());
}
else
QItemDelegate::setEditorData(editor, index);
} void QCustomizedDelegate::setModelData ( QWidget * editor, QAbstractItemModel * model, const QModelIndex & index ) const
{
if(index.column()==) //第1列 班级
{
QComboBox *Cbox = dynamic_cast<QComboBox*>(editor);
model->setData(index,Cbox->currentText(),Qt::DisplayRole);
}
else if(index.column()==) //第2列 分数
{
QSpinBox *Sbox = dynamic_cast<QSpinBox*>(editor);
model->setData(index,Sbox->value(),Qt::DisplayRole);
}
else
QItemDelegate::setModelData(editor, model, index);
} void QCustomizedDelegate::updateEditorGeometry ( QWidget * editor, const QStyleOptionViewItem & option, const QModelIndex & index ) const
{
editor->setGeometry(option.rect);
}

然后,再通过视图的setItemDelegate(QAbstractItemDelegate * delegate )成员函数设置我们自定义的委托类对象即可

深入自定义委托类

之前我们写的自定义委托,每次都需要双击某个数据项,才能弹出编辑器

那如何让委托一直呈现在视图显示上呢?

步骤如下:

  • 重写委托类的paint成员函数
  • 在paint()中,通过QApplication::style()->drawControl()来自定义数据显示方式,比如绘制按钮
  • 重写委托类的editorEvent成员函数
  • 在editorEvent中处理交互事件,比如判断鼠标是否双击,以及更改模型数据等

其中QApplication::style()->drawControl()函数参数如下所示:

QApplication::style()->drawControl (ControlElement element,
                     constQStyleOption * option,
                      QPainter *painter, const QWidget * widget = ) ; //绘画组件
// element: 元素,用来指定控件样式,比如: QStyle::CE_CheckBox 表示绘画的widget是一个text文本的复选框 // option:选项,用来绘制控件所需的所有参数比如option.rect(设置组件大小位置), option.state(设置组件状态)

//其中option. state成员值常见的有:
  QStyle::State_Enabled //表示该组件是激活的,可以被用户操作
  QStyle::State_On //表示该组件样式是被选上的
  QStyle::State_Off //表示该组件样式是未被选中的
  QStyle::State_MouseOver //表示表示该组件样式是:鼠标停留在组件上面的样子
  QStyle::State_Sunken //表示该组件样式是:鼠标按压下的组件样子
  QStyle::State_HasEditFocus //表示该组件是否有编辑焦点 // painter:谁来绘画 // widget = 0:如果该widget为0,则表示使用QT自带的风格

示例-自定义一个QCostomizedDelegate委托类

效果如下

代码如下

QCustomizedDelegate.h:

#ifndef QCUSTOMIZEDDELEGATE_H
#define QCUSTOMIZEDDELEGATE_H #include <QItemDelegate>
#include <QtGui>
#include "ProgressBar.h" class QCustomizedDelegate : public QItemDelegate
{
Q_OBJECT
//m_bar:温度台的当前温度进度条
QScopedPointer<QProgressBar> m_bar ; public:
explicit QCustomizedDelegate(QObject *parent = );
void paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const;
bool editorEvent ( QEvent * event, QAbstractItemModel * model, const QStyleOptionViewItem & option, const QModelIndex & index ); }; #endif // QCUSTOMIZEDDELEGATE_H

QCustomizedDelegate.cpp:

#include "QCustomizedDelegate.h"
#include "ProgressBar.h" QCustomizedDelegate::QCustomizedDelegate(QObject *parent) :
QItemDelegate(parent),
m_bar(new QProgressBar())
{
m_bar->setStyleSheet(qApp->styleSheet()); //设置风格
} void QCustomizedDelegate::paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const
{
if(index.column()== && index.data().type() == QVariant::Int) //判断列数,并判断索引值是否int型(温度是通过int型值表示的)
{
int radio=;
int top = option.rect.top() + radio;
int left = option.rect.left() + radio;
int width = option.rect.width() - * radio;
int height = option.rect.height() - * radio; QStyleOptionProgressBar bar; //设置参数
bar.rect.setRect(left, top, width, height);
bar.state = QStyle::State_Enabled;
bar.progress = index.data().toInt();
bar.maximum = ;
bar.minimum = ;
bar.textVisible = true;
bar.text = QString("当前温度:%1°").arg(bar.progress);
bar.textAlignment = Qt::AlignCenter; QApplication::style()->drawControl(QStyle::CE_ProgressBar,&bar,painter, m_bar.data());
}
else
{
QItemDelegate::paint(painter,option,index);
}
} bool QCustomizedDelegate::editorEvent ( QEvent * event, QAbstractItemModel * model, const QStyleOptionViewItem & option, const QModelIndex & index )
{
if(event->type() == QEvent::MouseButtonDblClick) //禁止双击编辑
{
return true;
}
return QItemDelegate::editorEvent(event,model,option,index);
}

26.QT-模型视图之自定义委托的更多相关文章

  1. Qt之模型/视图(自定义进度条)

    简述 在之前的章节中分享过关于QHeaderView表头排序.添加复选框等内容,相信大家模型/视图.自定义风格有了一定的了解,下面我们来分享一个更常用的内容-自定义进度条. 实现方式: 从QAbstr ...

  2. Qt之模型/视图(自定义风格)

    Qt之模型/视图(自定义风格) 关于自定义风格是针对视图与委托而言的,使用事件与QSS都可以进行处理,今天关于美化的细节讲解一下. 先看下图: 先撇开界面的美观性(萝卜青菜,各有所爱),就现有的这些风 ...

  3. Qt模型/视图、委托

    MVC视图和控制器对象相结合,其结果是模型/视图结构,仍然分离了数据与呈现给用户的方式,使得它可以在几个不同的视图中显示相同的数据,并实现新类型的视图而无需改变底层的数据结构.为了灵活的处理数据输入, ...

  4. Qt 模型/视图/委托

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

  5. 38.Qt模型/视图结构

    1.模型/视图类 2.模型 3.视图 4.代理 1 模型/视图类 InterView框架提供了一些可以直接使用的模型类和视图类,如QStandardModel类,QDirModel类,QStringL ...

  6. Qt 模型/视图结构

    MVC是一种与用户界面相关的设计模式.通过使用此模型,可以有效地分离数据和用户界面.MVC设计模式包含三要素:表示数据的模型(Model).表示用户界面的视图(View)和定义了用户在界面上的操作控制 ...

  7. Qt模型/视图框架----简单的例子

    #include<qapplication.h> #include<qfilesystemmodel.h> #include<qtreeview.h> #inclu ...

  8. Qt之模型/视图(自定义按钮)

    简述 衍伸前面的章节,我们对QTableView实现了数据显示.自定义排序.显示复选框.进度条等功能的实现,本节主要针对自定义按钮进行讲解,这节过后,也希望大家对自定义有更深入的了解,在以后的功能开发 ...

  9. Qt 之模型/视图(自定义按钮)

    https://blog.csdn.net/liang19890820/article/details/50974059 简述 衍伸前面的章节,我们对QTableView实现了数据显示.自定义排序.显 ...

随机推荐

  1. Asp.net Identity框架

    Identity提供基于用户和角色的membership管理框架,基本上可以满足业务项目登录操作的所有功能需求. 如果要使用这套框架需要新建User和Role类型分别继承自IUser<TKey& ...

  2. ubuntu 16.04安装mysql

    首先执行下面三条命令: sudo apt-get install mysql-server sudo apt install mysql-client sudo apt install libmysq ...

  3. C 单向链表就地逆转

    1.问题描述 给定一个单链表L,设计函数Reverse将L就地逆转.即不需要申请新的节点,将第一个节点转换为最后一个结点,第二个节点转换为倒数第二个结点,以此类推. 2.思路分析 循环处理整个链表.将 ...

  4. 解决微信小程序登录与发布的一些问题

    解决微信小程序的问题 图片在电脑上显示但在手机上却无法显示的问题 要使用的是本地图片,不想把图片上传到网络再通过https的方式解决,解决方法如下: 1.image src中的图片地址对英文字母大小写 ...

  5. 如何使用 GDB

    前期准备 启动GDB方法 设置运行参数 查看源码 断点break 使用 运行程序 查看运行时数据 查看内存数据 分割窗口 问题汇总 参考文献 GDB, The GNU Project debugger ...

  6. python pip 安装库文件报错:pip install ImportError: No module named _internal

    解决方法: pip2.7, you can at first curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py then python2. ...

  7. KNN算法基本实例

    KNN算法是机器学习领域中一个最基本的经典算法.它属于无监督学习领域的算法并且在模式识别,数据挖掘和特征提取领域有着广泛的应用. 给定一些预处理数据,通过一个属性把这些分类坐标分成不同的组.这就是KN ...

  8. [Objective-C语言教程]关系运算符(8)

    运算符是一个符号,告诉编译器执行特定的数学或逻辑操作. Objective-C语言内置很多运算符,提供如下类型的运算符 - 算术运算符 关系运算符 逻辑运算符 按位运算符 分配运算符 其它运算符 本教 ...

  9. 浅谈模块系统与 ABP 框架初始化

    在 ABP 框架当中所有库以及项目都是以模块的形式存在,所有模块都是继承自AbpModule 这个抽象基类,每个模块都拥有四个生命周期.分别是: PreInitialze(); Initialize( ...

  10. VueJs(1)---快速上手VueJs

    [VueJs入门] 版权声明 首先申明:此篇博客不是本人原创,只是最近开始学习vue.jS,看到有作者写的很不错,我仅在它的基础上仅仅是修改了样式 原文博客地址:https://blog.csdn.n ...