26.QT-模型视图之自定义委托

 在上一章学习 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 = 0);

    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)           //第1列 班级
    {
        QComboBox   *Cbox = new QComboBox(parent);
        Cbox->addItems(QStringList()<<"1班"<<"2班"<<"3班"<<"4班"<<"5班");
        return Cbox;
    }
    else if(index.column()==2)           //第2列 分数
    {
        QSpinBox    *Sbox = new QSpinBox(parent);
        Sbox->setRange(0,150);
        return Sbox;
    }

    return QItemDelegate::createEditor(parent, option, index);      //第0列,则选择默认编辑器
}

void QCustomizedDelegate::setEditorData ( QWidget * editor, const QModelIndex & index ) const
{
    if(index.column()==1)           //第1列 班级
    {
        QComboBox   *Cbox = dynamic_cast<QComboBox*>(editor);
        Cbox->setCurrentIndex(Cbox->findText( index.data(Qt::DisplayRole).toString()));
    }
    else if(index.column()==2)           //第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)           //第1列 班级
    {
        QComboBox   *Cbox = dynamic_cast<QComboBox*>(editor);
        model->setData(index,Cbox->currentText(),Qt::DisplayRole);
    }
    else if(index.column()==2)           //第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 = 0 ) ;

//绘画组件
// 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 = 0);
    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()==1 && index.data().type() == QVariant::Int)     //判断列数,并判断索引值是否int型(温度是通过int型值表示的)
    {
        int radio=14;
        int top = option.rect.top() + radio;
        int left = option.rect.left() + radio;
        int width = option.rect.width() - 2 * radio;
        int height = option.rect.height() - 2 * radio;

        QStyleOptionProgressBar bar;                   //设置参数
        bar.rect.setRect(left, top, width, height);
        bar.state  = QStyle::State_Enabled;
        bar.progress = index.data().toInt();
        bar.maximum = 100;
        bar.minimum = 0;
        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);
}

原文地址:https://www.cnblogs.com/lifexy/p/9186565.html

时间: 2024-10-11 18:31:23

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

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

Qt之模型/视图(自定义风格) 关于自定义风格是针对视图与委托而言的,使用事件与QSS都可以进行处理,今天关于美化的细节讲解一下. 先看下图: 先撇开界面的美观性(萝卜青菜,各有所爱),就现有的这些风格,使用QSS + Qt二维绘图已经绰绰有余了.当然,如何让界面更美观,这个没有什么捷径,我只能说一句:无他,唯手熟尔!基本功搞扎实了,实现起来就会游刃有余...void DetailProgressBar::paint(QPainter *painter, const QStyleOptionVi

QT 模型/视图 编程 委托篇

委托类 概述 与模型-视图-控制器模式不同,模型/视图设计不包括用于管理与用户交互的完全独立的组件.通常,视图负责向用户表示模型数据,并处理用户输入.为了在获取输入的方式上允许一定的灵活性,交互由委托执行.这些组件提供输入功能,并负责在某些视图中呈现各个项.控制委托的标准接口在QAbstractItemDelegate类中定义. 委托应该能够通过实现paint()和sizeHint()函数来呈现它们自己的内容.然而,简单的基于widget的委托可以子类化QItemDelegate而不是QAbst

QT——模型/视图(model/view)

数据项中引入模型/视图架构,可以方便的将数据与表现层分开. ------------------------------------- 模型Model:一般来说,Model里面并不真正存储数据(数据少的话也可以直接存储在Model里),只是负责从诸如磁盘文件,数据库,网络通讯等获得源数据,并提供给View,View对数据进行修改,然后再通过Model更新源数据. Model 另一个重要工作时为源数据添加索引(ModelIndex).列表形式采用row/colum编号,树形式为建立父子间的层次关系

Qt模型/视图中的data和headerData

QAbstractItemModel QAbstractItemModel是一个抽象类,该抽象类未实现的纯虚方法有 QModelIndex QAbstractItemModel::index(int row, int column, const QModelIndex & parent = QModelIndex()) const [pure virtual] QModelIndex QAbstractItemModel::parent(const QModelIndex & index)

Qt模型/视图、委托

MVC视图和控制器对象相结合,其结果是模型/视图结构,仍然分离了数据与呈现给用户的方式,使得它可以在几个不同的视图中显示相同的数据,并实现新类型的视图而无需改变底层的数据结构.为了灵活的处理数据输入,则引入委托的概念.在此框架中引入委托的有点事:允许项目数据显示和自定义编辑. 模型与数据源进行通信,在这个体系结构中为其它组件提供了一个接口.通信的性质依赖于数据源的类型以及模型的实现方式. 视图从模型中得到模型索引,这些都是引用到数据项.通过为模型提供模型索引,视图可以从数据远中检索数据项. 在标

38.Qt模型/视图结构

1 模型/视图类 InterView框架提供了一些可以直接使用的模型类和视图类,如QStandardModel类,QDirModel类,QStringListModel类,以及QColumnView类,QHeaderView类,QListView类,QTableView类和QTreeView类 简单目录浏览器: 1 #include "mainwindow.h" 2 #include <QApplication> 3 4 #include <QAbstractItem

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

简述 衍伸前面的章节,我们对QTableView实现了数据显示.自定义排序.显示复选框.进度条等功能的实现,本节主要针对自定义按钮进行讲解,这节过后,也希望大家对自定义有更深入的了解,在以后的功能开发过程中,相信无论遇到什么样式形式,我们都可以很好地实现. 简述 效果 QStyledItemDelegate 源码 衍伸 效果 QStyledItemDelegate 源码 .h 包含显示按钮需要用到的智能指针,按钮的宽度.高度.按钮之间的间距.鼠标的坐标等. class TableViewDele

QT开发(八)——QT单元视图组件

QT开发(八)--QT单元视图组件 QT中有四种单元视图组件,分别为列表视图QListView.树形视图QTreeView.表格视图QTableView.列视图QColumnView. 一.QListView列表视图 1.QListView组件简介 QListView列表视图,继承自QAbstractItemView.QListView是基于模型的列表/图标视图,不显示表头和表框,为Qt的模型/视图结构提供了更灵活的方式. 2.QListView组件属性 QListView组件属性设置: A.n

第61课 模型视图中的委托(上)

1. Qt模型视图对用户输入的处理 (1)传统的MVC设计模式 (2)Qt中的模型视图设计模式如何处理用户输入? ①视图中集成了处理用户输入的功能(即委托) ②视图将用户输入作为内部独立的子功能来实现 ③模型负责组织数据,视图负责显示数据,委托则用于编辑修改数据. 2. 模型视图中的委托 (1)委托(Delegate)是视图中处理用户输入的部件(如编辑框.单选按钮等) (2)视图可以设置委托对象用于处理用户输入 (3)委托对象负责创建和显示用户输入的上下文(内容),如编辑框的创建和显示. (4)