1、自定义委托
委托的本质
-为视图提供数据编辑的上下文环境
-产生界面元素的工厂类
-能够使用和设置模型中的数据
如何自定义一个委托类?
自定义委托时需要重写的函数
1. createEditor
2. updateEditorGeometry
3. setEditorData
4. setModelData
5. paint (可选)
1. 重写creatorEditor成员函数
- 根据索引中值的类型创建编辑器组件
QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QWidget* ret = NULL;
if( index.data().type() == QVariant::Bool )
{
//当前数据项中的数据类型是bool型,创建QCheckBox组件(复选框)
QCheckBox* cb = new QCheckBox(parent);
cb->setText("Check to TRUE");
ret = cb;
}
else if( index.data().type() == QVariant::Char )
{
//当前数据项中的数据类型是char型,创建QComboBox组件(下拉列表框)
QComboBox* cb = new QComboBox(parent);
cb->addItem("A");
cb->addItem("B");
cb->addItem("C");
cb->addItem("D");
ret = cb;
}
else
{
//其它情况,直接使用父类提供的默认创建编辑器组件方式
ret = QItemDelegate::createEditor(parent, option, index);
}
return ret;
}
2. 重写updateEditorGeometry成员函数
- 根据参数中数据项的信息设置编辑器的位置和大小
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
editor->setGeometry(option.rect);
}
3. 重写setEditorData成员函数
- 根据参数中的数据索引设置编辑器中的初始数据
void setEditorData(QWidget *editor, const QModelIndex &index) const
{
if( index.data().type() == QVariant::Bool )
{
QCheckBox* cb = dynamic_cast<QCheckBox*>(editor);
if( cb != NULL )
{
cb->setChecked(index.data().toBool());//设置设置复选框组件被选中
}
}
else if( index.data().type() == QVariant::Char )
{
QComboBox* cb = dynamic_cast<QComboBox*>(editor);
if( cb != NULL )
{
for(int i=0; i<cb->count(); i++)//遍历下拉列表所有选项
{
if( cb->itemText(i) == index.data().toString() ) //选项和当前模型数据一样
{
cb->setCurrentIndex(i);//设置下拉列表组件当前选项应该选择哪个
break;
}
}
}
}
else
{
QItemDelegate::setEditorData(editor, index);
}
}
4. 重写setModelData成员函数
- 根据参数中的数据索引更改模型中的数据
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
if( index.data().type() == QVariant::Bool )
{
QCheckBox* cb = dynamic_cast<QCheckBox*>(editor);
if( cb != NULL )
{
model->setData(index, cb->isChecked(), Qt::DisplayRole);//将复选框值(role data )取出,根据索引设置到模型
}
}
else if( index.data().type() == QVariant::Char )
{
QComboBox* cb = dynamic_cast<QComboBox*>(editor);
if( cb != NULL )
{
model->setData(index, cb->currentText().at(0), Qt::DisplayRole);
}
}
else
{
QItemDelegate::setModelData(editor, model, index);
}
}
5. 重写paint成员函数(可选)
- 根据参数中的信息绘制编辑器
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if( condition )
{
//customized paint action
}
else
{
QItemDelegate::paint(painter, option, index);
}
}
2、编程实验
自定义委托 62-1.pro
CustomizedItemDelegate.h
#ifndef CUSTOMIZEDITEMDELEGATE_H
#define CUSTOMIZEDITEMDELEGATE_H
#include <QItemDelegate>
#include <QModelIndex>
class CustomizedItemDelegate : public QItemDelegate //自定义委托类,继承自标准委托类
{
Q_OBJECT
mutable QModelIndex m_index;
protected slots:
void onCloseEditor(QWidget*);
public:
explicit CustomizedItemDelegate(QObject *parent = 0);
//重写一系列函数
QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;
void updateEditorGeometry(QWidget *editor, 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 paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
};
#endif // CUSTOMIZEDITEMDELEGATE_H
CustomizedItemDelegate.cpp
#include "CustomizedItemDelegate.h"
#include <QCheckBox>
#include <QComboBox>
CustomizedItemDelegate::CustomizedItemDelegate(QObject *parent) :
QItemDelegate(parent)
{
connect(this, SIGNAL(closeEditor(QWidget*)), this, SLOT(onCloseEditor(QWidget*)));
}
QWidget* CustomizedItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QWidget* ret = NULL;
m_index = index; //记录被当前被编辑数据项索引
if( index.data().type() == QVariant::Bool )
{
//当前数据项中的数据类型是bool型,创建QCheckBox组件(复选框)
QCheckBox* cb = new QCheckBox(parent);
cb->setText("Check to TRUE");
ret = cb;
}
else if( index.data().type() == QVariant::Char )
{
//当前数据项中的数据类型是char型,创建QComboBox组件(下拉列表框)
QComboBox* cb = new QComboBox(parent);
cb->addItem("A");
cb->addItem("B");
cb->addItem("C");
cb->addItem("D");
ret = cb;
}
else
{
//其它情况,直接使用父类提供的默认创建编辑器组件方式
ret = QItemDelegate::createEditor(parent, option, index);
}
return ret; //返回创建的编辑器组件
}
void CustomizedItemDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
editor->setGeometry(option.rect);
}
void CustomizedItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
if( index.data().type() == QVariant::Bool )
{
QCheckBox* cb = dynamic_cast<QCheckBox*>(editor);
if( cb != NULL )
{
cb->setChecked(index.data().toBool());//设置设置复选框组件被选中
}
}
else if( index.data().type() == QVariant::Char )
{
QComboBox* cb = dynamic_cast<QComboBox*>(editor);
if( cb != NULL )
{
for(int i=0; i<cb->count(); i++)//遍历下拉列表所有选项
{
if( cb->itemText(i) == index.data().toString() ) //选项和当前模型数据一样
{
cb->setCurrentIndex(i);//设置下拉列表组件当前选项应该选择哪个
break;
}
}
}
}
else
{
QItemDelegate::setEditorData(editor, index);
}
}
void CustomizedItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
if( index.data().type() == QVariant::Bool )
{
QCheckBox* cb = dynamic_cast<QCheckBox*>(editor);
if( cb != NULL )
{
model->setData(index, cb->isChecked(), Qt::DisplayRole);//将复选框值(role data )取出,根据索引设置到模型
}
}
else if( index.data().type() == QVariant::Char )
{
QComboBox* cb = dynamic_cast<QComboBox*>(editor);
if( cb != NULL )
{
model->setData(index, cb->currentText().at(0), Qt::DisplayRole);
}
}
else
{
QItemDelegate::setModelData(editor, model, index);
}
}
void CustomizedItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if( m_index != index ) //不是当前被编辑数据项索引才进行绘制
{
QItemDelegate::paint(painter, option, index);
}
}
void CustomizedItemDelegate::onCloseEditor(QWidget*)
{
m_index = QModelIndex(); //关闭编辑框时将当前记录的索引清空
}
Widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QtGui/QWidget>
#include <QTableView>
#include <QStandardItemModel>
#include <QPushButton>
#include "CustomizedItemDelegate.h"
class Widget : public QWidget
{
Q_OBJECT
QTableView m_view;
QStandardItemModel m_model;
CustomizedItemDelegate m_delegate;
void initView();
void initModel();
public:
Widget(QWidget* parent = 0);
~Widget();
};
#endif // WIDGET_H
Widget.cpp
#include "Widget.h"
#include <QStandardItem>
#include <QModelIndex>
#include <QStringList>
#include <QDebug>
Widget::Widget(QWidget* parent) : QWidget(parent)
{
initView();
initModel();
m_view.setModel(&m_model);
for(int i=0; i<m_model.columnCount(); i++)
{
m_view.setColumnWidth(i, 125);
}
}
void Widget::initView()
{
m_view.setParent(this);
m_view.move(10, 10);
m_view.resize(500, 200);
m_view.setItemDelegate(&m_delegate); //将自定义委托设到视图
}
void Widget::initModel()
{
QStandardItem* root = m_model.invisibleRootItem();
QStringList hl;
QStandardItem* itemA1 = new QStandardItem();
QStandardItem* itemB1 = new QStandardItem();
QStandardItem* itemC1 = new QStandardItem();
QStandardItem* itemA2 = new QStandardItem();
QStandardItem* itemB2 = new QStandardItem();
QStandardItem* itemC2 = new QStandardItem();
hl.append("Language");
hl.append("Level");
hl.append("Script");
m_model.setHorizontalHeaderLabels(hl);
itemA1->setData("Delphi", Qt::DisplayRole);
itemB1->setData(QChar('A'), Qt::DisplayRole);
itemC1->setData(false, Qt::DisplayRole);
itemA2->setData("Perl", Qt::DisplayRole);
itemB2->setData(QChar('B'), Qt::DisplayRole);
itemC2->setData(true, Qt::DisplayRole);
root->setChild(0, 0, itemA1);
root->setChild(0, 1, itemB1);
root->setChild(0, 2, itemC1);
root->setChild(1, 0, itemA2);
root->setChild(1, 1, itemB2);
root->setChild(1, 2, itemC2);
}
Widget::~Widget()
{
}
main.cpp
#include <QtGui/QApplication>
#include "Widget.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
问题
自定义委托时重写的函数由谁调用?
单步调试可得是视图
3、小结
自定委托类时需要重写相应的成员函数
根据需要创建编辑组件并设置组件中的数据
编辑结束后将数据返回模型
成员函数的参数携带了数据存取时需要的信息