Qt自定义代理与实例

1. 代理的定义

代理(Delegate)就是在视图组件上为编辑数据提供编辑器,如在表格组件中编辑一个单元格的数据时,缺省是使用一个QLineEdit编辑框。代理负责从数据模型获取相应的数据,然后显示在编辑器里,修改数据后,又将其保存到数据模型中。

QAbstractItemDelegate是所有代理类的基类,作为抽象类,它不能直接使用。它的一个子类QStyledItemDelegate,是Qt的视图组件缺省使用的代理类。

对于一些特殊的数据编辑需求,例如只允许输入整型数,使用一个QSpinBox作为代理组件更恰当,从列表中选择数据时使用一个QComboBox作为代理组件更好。这时,就可以从QStyledItemDelegate继承创建自定义代理类

2. 自定义代理的功能

当我们导入数据文件进行编辑时,QTableView组件为每个单元格提供的是缺省的代理编辑组件,就是一个QLineEdit组件。

在编辑框里可以输入任何数据,所以比较通用。但是有些情况下,希望根据数据的类型限定使用不同的编辑组件,例如第1列我们要求是整数,使用QSpinBox作为编辑组件更合适

3. 自定义代理类的基本要求

image-20210726092312517

不管从QStyledItemDelegate还是QItemDelegate继承设计自定义代理组件,都必须实现如下的4个函数:

  • createEditor()函数创建用于编辑模型数据的 widget组件,如一个QSpinBox组件,或一个QComboBox 组件;
  • setEditorData()函数从数据模型获取数据,供 widget组件进行编辑;
  • setModelData()将 widget上的数据更新到数据模型;
  • updateEditorGeometry()用于给widget组件设置一个合适的大小。

4. 实例

4.1 效果演示

我们要实现的就是,弄一个表格,当我们编辑数据的时候,能够有下图所示的效果

image-20210726092952169

而不是单独的文本编辑框,还有下面这种spinbox

image-20210726093118857

4.2 关键代码分析

为了方便起见,我们采用spinbox的代理类来讲解具体的代码

首先要记得,我们得实现4个函数

createEditor() 创建用于编辑模型数据的 widget组件

static string MyBlog = "https://www.cnblogs.com/wanghongyang";

QWidget *SpinDelegate::createEditor(QWidget *parent,const QStyleOptionViewItem &/*option*/,const QModelIndex &/*index*/) const
{
    QSpinBox *editor = new QSpinBox(parent);
    editor->setRange(0,10000);
    editor->installEventFilter(const_cast<SpinDelegate*>(this));

    return editor;
}

这里创建了一个spinbox组件,设置范围,安装过滤器,我们来看看这个过滤器的用法

void QObject::installEventFilter(QObject *filterObj)

在这个对象上安装一个事件过滤器filterObj

事件筛选器是一个对象,它接收发送到此对象的所有事件。过滤器可以停止事件,也可以将事件转发给该对象。事件过滤器filterObj通过其eventFilter()函数接收事件。eventFilter()函数必须返回true,如果事件应该被过滤(即停止);否则它必须返回false。

如果在单个对象上安装多个事件筛选器,最后安装的筛选器将首先激活。

看到这里const_cast有些不明白,我们再来看看const_cast

const_cast转换符是用来移除变量的const或volatile限定符

**setEditorData() **从数据模型获取数据,供 widget组件进行编辑

void SpinDelegate::setEditorData(QWidget *editor,const QModelIndex &index) const
{
    int value =index.model()->data(index).toInt();
    QSpinBox *box = static_cast<QSpinBox*>(editor);
    box->setValue(value);
}

函数重模型中获得数据,然后设置数据给组件进行编辑

setModelData() 将 widget上的数据更新到数据模型

void SpinDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,const QModelIndex &index) const
{
    QSpinBox *box = static_cast<QSpinBox*>(editor);
    int value = box->value();

    model->setData(index,value);
}

代码浅显易懂,不过多赘述

updateEditorGeometry() 给widget组件设置一个合适的大小

void SpinDelegate::updateEditorGeometry(QWidget *editor,const QStyleOptionViewItem &option, const QModelIndex &/*index*/) const
{
    editor->setGeometry(option.rect);
}

接下来我们看看这些函数的具体使用

在main函数中设置代理,通过列的方式

SpinDelegate spinDelegate;
tableView.setItemDelegateForColumn(3,&spinDelegate);

这样就可以使用自定义代理了

4. 扩展

其他一些关于模型的细节,大家可以看看我之前的文章

https://www.cnblogs.com/wanghongyang/p/15017253.html

https://www.cnblogs.com/wanghongyang/p/15037968.html

posted @ 2021-07-26 14:16  进击的汪sir  阅读(1818)  评论(1编辑  收藏  举报