在上一节中,导入数据文件进行编辑时, QTableView组件为每个单元格提供的是缺省的代理编辑组件,就是一个QLineedit组件。在编辑框里可以输入任何数据,所以比较通用。但是有些情况下,希望根据数据的类型限定使用不同的编辑组件,例如在上节的实例的数据中,第1列“测深”是整数,使用 QSpinBox作为编辑组件更合适;“垂深”“方位”“总位移”是浮点数,使用 QDoubleSpin Box更合适;而“固井质量”使用一个 ComboBox,从一组列表文字中选择更合适。要实现这些功能,就需要为 TableView的某列或某个单元格设置自定义代理组件
在上节中的例子中增加代理类的效果如下
2自定义代理类的基本设计要求
Qt中有关代理的几个类的层次结构如图
QAbstractltem Delegate是所有代理类的抽象基类, QStyledltemDelegate是视图组件使用的缺
省的代理类, QItemDelegate也是类似功能的类。QStyledItemDelegate与 QItemDelegate的差别在于:QStyledltemDelegate可以使用当前的样式表设置来绘制组件,因此建议使用 QStyledltemDelegate作为自定义代理组件的基类。
不管从 QStyledltemDelegate还是 QItemDelegate继承设计自定义代理组件,都必须实现如下
的4个函数:
createEditor函数创建用于编辑模型数据的 widget组件,如一个 QSpinBox组件,或一个
ComboBox组件;
setEditorData函数从数据模型获取数据,供 widget组件进行编辑;
setModelData将 widget上的数据更新到数据模型;
updateEditorGeometry用于给 widget组件设置一个合适的大小
在上节的例子中新增三个类,QComboBoxDelegate、QFloatSpinDelegate、QIntSpinDelegate
QComboBoxDelegate类的设计代码如下:
#pragma once
#include <QItemDelegate>
class QComboBoxDelegate : public QItemDelegate
{
Q_OBJECT
public:
QComboBoxDelegate(QObject* parent = 0);
~QComboBoxDelegate();
//自定义代理组件必须继承以下4个函数
QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option,
const QModelIndex& index) const Q_DECL_OVERRIDE;
void setEditorData(QWidget* editor, const QModelIndex& index) const Q_DECL_OVERRIDE;
void setModelData(QWidget* editor, QAbstractItemModel* model,
const QModelIndex& index) const Q_DECL_OVERRIDE;
void updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option,
const QModelIndex& index) const Q_DECL_OVERRIDE;
};
#include "QComboBoxDelegate.h"
#include <QComboBox>
QComboBoxDelegate::QComboBoxDelegate(QObject *parent)
: QItemDelegate(parent)
{
}
QComboBoxDelegate::~QComboBoxDelegate()
{
}
QWidget* QComboBoxDelegate::createEditor(QWidget* parent,
const QStyleOptionViewItem& option, const QModelIndex& index) const
{
QComboBox* editor = new QComboBox(parent);
editor->addItem(QStringLiteral("优"));
editor->addItem(QStringLiteral("良"));
editor->addItem(QStringLiteral("一般"));
editor->addItem(QStringLiteral("不合格"));
return editor;
}
void QComboBoxDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
{
QString str = index.model()->data(index, Qt::EditRole).toString();
QComboBox* comboBox = static_cast<QComboBox*>(editor);
comboBox->setCurrentText(str);
}
void QComboBoxDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const
{
QComboBox* comboBox = static_cast<QComboBox*>(editor);
QString str = comboBox->currentText();
model->setData(index, str, Qt::EditRole);
}
void QComboBoxDelegate::updateEditorGeometry(QWidget* editor,
const QStyleOptionViewItem& option, const QModelIndex& index) const
{
editor->setGeometry(option.rect);
}
QFloatSpinDelegate类的设计代码如下
#pragma once
#include <QStyledItemDelegate>
class QFloatSpinDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
QFloatSpinDelegate(QObject* parent = 0);
~QFloatSpinDelegate();
//自定义代理组件必须继承以下4个函数
QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option,
const QModelIndex& index) const Q_DECL_OVERRIDE;
void setEditorData(QWidget* editor, const QModelIndex& index) const Q_DECL_OVERRIDE;
void setModelData(QWidget* editor, QAbstractItemModel* model,
const QModelIndex& index) const Q_DECL_OVERRIDE;
void updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option,
const QModelIndex& index) const Q_DECL_OVERRIDE;
};
#include "QFloatSpinDelegate.h"
#include <QDoubleSpinBox>
QFloatSpinDelegate::QFloatSpinDelegate(QObject *parent)
: QStyledItemDelegate(parent)
{
}
QFloatSpinDelegate::~QFloatSpinDelegate()
{
}
QWidget* QFloatSpinDelegate::createEditor(QWidget* parent,
const QStyleOptionViewItem& option, const QModelIndex& index) const
{
Q_UNUSED(option);
Q_UNUSED(index);
QDoubleSpinBox* editor = new QDoubleSpinBox(parent);
editor->setFrame(false);
editor->setMinimum(0);
editor->setDecimals(2);
editor->setMaximum(10000);
return editor;
}
void QFloatSpinDelegate::setEditorData(QWidget* editor,
const QModelIndex& index) const
{
float value = index.model()->data(index, Qt::EditRole).toFloat();
QDoubleSpinBox* spinBox = static_cast<QDoubleSpinBox*>(editor);
spinBox->setValue(value);
}
void QFloatSpinDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const
{
QDoubleSpinBox* spinBox = static_cast<QDoubleSpinBox*>(editor);
spinBox->interpretText();
float value = spinBox->value();
QString str = QString::asprintf("%.2f", value);
model->setData(index, str, Qt::EditRole);
}
void QFloatSpinDelegate::updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
editor->setGeometry(option.rect);
}
QIntSpinDelegate类的设计代码如下:
#pragma once
#include <QStyledItemDelegate>
class QIntSpinDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
QIntSpinDelegate(QObject* parent = 0);
~QIntSpinDelegate();
//自定义代理组件必须继承以下4个函数
//创建编辑组件
QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option,
const QModelIndex& index) const Q_DECL_OVERRIDE;
//从数据模型获取数据,显示到代理组件中
void setEditorData(QWidget* editor, const QModelIndex& index) const Q_DECL_OVERRIDE;
//将代理组件的数据,保存到数据模型中
void setModelData(QWidget* editor, QAbstractItemModel* model,
const QModelIndex& index) const Q_DECL_OVERRIDE;
//更新代理编辑组件的大小
void updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option,
const QModelIndex& index) const Q_DECL_OVERRIDE;
};
#include "QIntSpinDelegate.h"
#include <QSpinBox>
QIntSpinDelegate::QIntSpinDelegate(QObject *parent)
: QStyledItemDelegate(parent)
{
}
QIntSpinDelegate::~QIntSpinDelegate()
{
}
QWidget* QIntSpinDelegate::createEditor(QWidget* parent,
const QStyleOptionViewItem& option, const QModelIndex& index) const
{
//创建代理编辑组件
Q_UNUSED(option);
Q_UNUSED(index);
QSpinBox* editor = new QSpinBox(parent); //创建一个QSpinBox
editor->setFrame(false); //设置为无边框
editor->setMinimum(0);
editor->setMaximum(10000);
return editor; //返回此编辑器
}
void QIntSpinDelegate::setEditorData(QWidget* editor,
const QModelIndex& index) const
{
//从数据模型获取数据,显示到代理组件中
//获取数据模型的模型索引指向的单元的数据
int value = index.model()->data(index, Qt::EditRole).toInt();
QSpinBox* spinBox = static_cast<QSpinBox*>(editor);