Qt5Demo-如何为QTableView创建自定义委托
SpinBox Delegate Example
这个例子介绍如何在model/view中为编辑控件创造一个定制的委托框架,带来达到将将标准的Qt输入控件嵌入到模型视图的效果
model/view开发矿建提供了一个标准的委托,我们在使用标准的视图控件中,会用到默认的委托,在大多数情况下编辑控件足够我们输入比如文本,布尔,或者其他简单的数据类型,然而,对于一些特殊的数据类型,有时候我们有必要使用定制的委托来编辑或者显示这些数据,或者使用定制的控件
本节中的思想将会在 Delegate 类中集中说明
SpinBoxDelegate Class的实现
关于此委托的实现如下
class SpinBoxDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
SpinBoxDelegate(QObject *parent = nullptr);
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
const QModelIndex &index) const override;
void setEditorData(QWidget *editor, const QModelIndex &index) const override;
void setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const override;
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,
const QModelIndex &index) const override;
};
Delegate 类仅仅声明了如下的函数,我么可以用这些函数来床架一个编辑控件窗口,并且将他们展示在一个现有的模型视图中,并且可以让他们和模型视图有关联,定制的委托也可以提供他们自己的painting code 通过重写paintEvent()函数,除此之外,还可以通过重写destroyEditor()函数来重用编辑控件窗口,这样的话,一个重用的窗口将会成为一个多态的对象,并在构造函数中创建,且在析构函数中被销毁。
SpinBoxDelegate Class的实现
委托通常是没有状态的,构造函数通常需要调用它的父类QObject的构造函数。
SpinBoxDelegate::SpinBoxDelegate(QObject *parent)
: QStyledItemDelegate(parent)
{
}
因为这个委托是继承于QStyleItemDelegate类的,它检索到的模型的数据是以默认的方式展示在view中的,并且我们不需要提供一个定制的paintEvent()
createEditor函数返回一个编辑控件窗口,一个SpinBox限制了模型的数据输入唉0-100之间
QWidget *SpinBoxDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &/* option */,
const QModelIndex &/* index */) const
{
QSpinBox *editor = new QSpinBox(parent);
editor->setFrame(false);
editor->setMinimum(0);
editor->setMaximum(100);
return editor;
}
我们在Spinbox中添加了一个事件过滤器,这样可以确保它和其他的委托保持一致,他是通过基类的事件过滤器来实现的
setEditorData()函数从model中去取数据,并将其转变为int型数据,并且将它写入到编辑控件窗口中
void SpinBoxDelegate::setEditorData(QWidget *editor,
const QModelIndex &index) const
{
int value = index.model()->data(index, Qt::EditRole).toInt();
QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
spinBox->setValue(value);
}
因为view处理的委托是源于QWidget格式的,所以我们不得不使用强制转换类型,这样我们才能得到SpinBox中的值
setModelData()函数,读取SpinBox中的值,并且将它写入到model中
void SpinBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const
{
QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
spinBox->interpretText();
int value = spinBox->value();
model->setData(index, value, Qt::EditRole);
}
我们调用interpretText()函数,却表我们能够得到SpinBox中实时更新的值。
updateEditorGeometry()函数,更显用户编辑窗口的几何结构,通过使用style选项中的信息,下面的函数是在本例中需要做的做少的事情
void SpinBoxDelegate::updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option,
const QModelIndex &/* index */) const
{
editor->setGeometry(option.rect);
}
更多的复杂 的编辑控件窗口可能需要使用option.rect类划分矩形窗口,如果有必要的话甚至需要包含一些子窗口
The main Function
这个例子和Qt提供的其他的例子有少许不同,为了在标准视图模型中去试验定制的编辑控件窗口,创建一个白喊预先定义的数据模型是非常有必要的
我们使用一种很普通的方法来创建这个应用,我们创建了一个包含一些数据的标准视图模型,然后创建了一个自定义委托用于编辑
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被委托来通知,并且该view将会显示所有的对象,因为Delegate是QStyleItemDelegate的子类,因此每一个单元都设置成这样。
我们还插入了一下预先定义好的数据在模型中
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();
}
github链接
https://github.com/chechem3/Delegate
VS源码
- dlegate.h
#pragma once
#include <QStyledItemDelegate>
class delegate : public QStyledItemDelegate
{
Q_OBJECT
public:
delegate(QObject *parent);
~delegate();
QWidget* createEditor(QWidget* parent,
const QStyleOptionViewItem& option,
const QModelIndex& index) const override;
void setEditorData(QWidget* editor, const QModelIndex& index) const override;
void setModelData(QWidget* editor, QAbstractItemModel* model,
const QModelIndex& index) const override;
void updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option,
const QModelIndex& index) const override;
};
- delegate.cpp
//这个委托是一个允许用户使用一个Spinbox来改变
//model里面的数值
#include "delegate.h"
#include <qspinbox.h>
delegate::delegate(QObject *parent)
: QStyledItemDelegate(parent)
{
}
delegate::~delegate()
{
}
QWidget* delegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
QSpinBox* editor = new QSpinBox(parent);
editor->setFrame(false);
editor->setMinimum(0);
editor->setMaximum(100);
return editor;
}
void delegate::setEditorData(QWidget* editor, const QModelIndex& index) const
{
int value = index.model()->data(index, Qt::EditRole).toInt();
QSpinBox* spinBox = static_cast<QSpinBox*>(editor);
//关于static_cast:属于C语言的强制数据类型转换,相当于把editor转变为QSpinBox*
spinBox->setValue(value);
}
void delegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const
{
QSpinBox* spinBox = static_cast<QSpinBox*>(editor);
spinBox->interpretText();
int value = spinBox->value();
model->setData(index, value, Qt::EditRole);
}
void delegate::updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
editor->setGeometry(option.rect);
}
- spinboxdelegate
#pragma once
#include <QtWidgets/QWidget>
#include <qstandarditemmodel.h>
#include "ui_spinboxdeleget.h"
#include "delegate.h"
class spinboxdeleget : public QWidget
{
Q_OBJECT
public:
spinboxdeleget(QWidget *parent = Q_NULLPTR);
private:
Ui::spinboxdelegetClass ui;
QStandardItemModel model;
delegate * delegate_1;
};
- spinboxdelegate.capp
#include "spinboxdeleget.h"
#include "delegate.h"
spinboxdeleget::spinboxdeleget(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
//QStandardItemModel model(4, 2);
model.setColumnCount(2);
model.setRowCount(4);
ui.tableView->setModel(&model);
//delegate delegate_1(nullptr);
delegate_1 = new delegate(NULL);
ui.tableView->setItemDelegate(delegate_1);
ui.tableView->horizontalHeader()->setStretchLastSection(true);
//setStretchLastSection:这个属性决定了在模型头中最后一个有效的部分
//是否占用有效的空间,默认的设置值是否
//由QTreeView提供的水平的头部分如果通过这个设置变为真,则这个View不会浪费任何
//头的空间
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)));
}
}
}