视图代理
代理就是一个中间人的意思,也就是model和view之间的一个中间件,它协调两者之间的数据处理,以保证数据在显示层和model层的一致性。
在qt中实现自己的一个代理,一般继承自QItemDelegate类,当然也可以是QAbstractItemDelegate。
在做代理的时候,我们首先要明确一些问题,我们的编辑控件是什么,设置它的值,修改怎么影响model,编辑控件的样式什么样,大小位置是否考虑。在qt中这些需要实现自己代理的方面都以虚函数的形式给出,在实现自己代理的时候,重新实现这些虚函数就行,而调用是自动的,这就是利用C++多态,实现了开闭。
下面给出一个例子
#ifndef SPINBOXDELEGATE_H
#define SPINBOXDELEGATE_H
#include <QItemDelegate>
#include <QModelIndex>
#include <QObject>
#include <QSize>
#include <QSpinBox>
#define logger() qDebug() << __FILE__ << __LINE__ << __func__
class SpinBoxDelegate : public QItemDelegate
{
Q_OBJECT
public:
SpinBoxDelegate(QObject *parent = 0);
/**
* @brief createEditor 进入可编辑的状态时,产生的编辑控件
* @param parent 这个控件的上层控件
* @param option 一些控件样式选择
* @param index 所在的索引位置
* @return 编辑控件的指针
*/
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
const QModelIndex &index) const;
/**
* @brief setEditorData 进入和推出编辑模式调用,修改view的值
* @param editor 与改变想对应的editor指针
* @param index model中的那个索引改变了值
*/
void setEditorData(QWidget *editor, const QModelIndex &index) const;
/**
* @brief setModelData 退出编辑模式,修改model
* @param editor 那个editor改变了
* @param model 想对应的model
* @param index 对应的索引
*/
void setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const;
/**
* @brief updateEditorGeometry 更新位置
* @param editor
* @param option
* @param index
*/
void updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option, const QModelIndex &index) const;
};
/**
这些虚函数是自动调用的,我们重新实现这些虚函数来达到控制的效果,可以重新实现的虚函数还有好几个,但是意义都是一样的
*/
#endif // SPINBOXDELEGATE_H
#include "spinBoxDelegate.h"
#include <QtGui>
#include <QDebug>
SpinBoxDelegate::SpinBoxDelegate(QObject *parent)
: QItemDelegate(parent)
{
}
QWidget *SpinBoxDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &/* option */,
const QModelIndex &/* index */) const
{
logger();
QSpinBox *editor = new QSpinBox(parent);//产生一个QSpinBox控件
editor->setMinimum(0);
editor->setMaximum(100);
return editor;
}
void SpinBoxDelegate::setEditorData(QWidget *editor,
const QModelIndex &index) const
{
logger();
int value = index.model()->data(index, Qt::EditRole).toInt();//根据index获得model的值
QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
spinBox->setValue(value);
}
void SpinBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const
{
logger();
QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
spinBox->interpretText();
int value = spinBox->value();
model->setData(index, value, Qt::EditRole);
}
void SpinBoxDelegate::updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option, const QModelIndex &/* index */) const
{
logger();
editor->setGeometry(option.rect);
}
#include <QApplication>
#include <QHeaderView>
#include <QItemSelectionModel>
#include <QStandardItemModel>
#include <QTableView>
#include "spinBoxDelegate.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QStandardItemModel model(4, 2);
QTableView tableView;
tableView.setModel(&model);
SpinBoxDelegate delegate;
tableView.setItemDelegate(&delegate);
tableView.horizontalHeader()->setStretchLastSection(true);
tableView.verticalHeader()->setStretchLastSection(true);
for (int row = 0; row < 4; ++row) {
for (int column = 0; column < 2; ++column) {
QModelIndex index = model.index(row, column, QModelIndex());
model.setData(index, QVariant((row+1) * (column+1)));
}
}
tableView.setWindowTitle(QObject::tr("Spin Box Delegate"));
tableView.show();
return app.exec();
}
可以根据打印的logger知道这些虚函数是怎么调用的,加深对整个框架运行机制的理解