第62课 - 模型视图中的委托(下) --- 自定义委托类

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、小结 

自定委托类时需要重写相应的成员函数 

根据需要创建编辑组件并设置组件中的数据 

编辑结束后将数据返回模型 

成员函数的参数携带了数据存取时需要的信息 

猜你喜欢

转载自blog.csdn.net/qq_39654127/article/details/81835788