在上一章学习 25.QT-模型视图 后,本章接着学习视图委托
视图委托(Delegate)简介
由于模型负责组织数据,而视图负责显示数据,所以当用户想修改显示的数据时,就要通过视图中的委托来完成
视图委托类似于传统的MVC设计模式里的Controller(控制器)角色
初探自定义委托类
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 ) ;
//当完成编辑数据后,发送该信号,表示有新数据提交到模型中
我们以编辑某个数据项为例:
接下来,我们重写上面函数,来自定义一个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 )成员函数设置我们自定义的委托类对象即可
深入自定义委托类
之前我们写的自定义委托,每次都需要双击某个数据项,才能弹出编辑器
那如何让委托一直呈现在视图显示上呢?
步骤如下:
其中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);
}