【Qt之模型视图】4. 委托及自定义委托

发布时间:2024年01月19日

1. 前言

与MVC架构(模型-视图-控制器模式)不同,模型/视图结构中不包括一个完全独立的组件来管理与用户的交互。通常,视图负责将模型数据呈现给用户,并处理用户输入。为了在获取输入的方式上提供一些灵活性,交互由委托完成。这些组件提供输入功能,并负责渲染某些视图中的单个项。控制委托的标准接口在QAbstractItemDelegate类中定义。
委托应能够通过实现paint()和sizeHint()函数自行渲染其内容。但是,简单基于小部件的委托可以将QItemDelegate作为QAbstractItemDelegate的子类,并利用这些函数的默认实现。
委托的编辑器可以通过使用小部件来管理编辑过程,或直接处理事件来实现。
Qt提供的标准视图使用QItemDelegate的实例提供编辑功能。默认委托接口的实现为标准视图(QListView、QTableView和QTreeView)中的每个项呈现常规样式。
默认委托处理了所有标准角色。
视图使用的委托由itemDelegate()函数返回。setItemDelegate()函数允许为标准视图安装自定义委托,在设置自定义视图的委托时需要使用此函数。

2. 自定义委托

接下来,使用自定义委托QSpinBox来提供编辑工具,主要用于显示整数的模型。
先设置一个自定义的基于整数的表模型QStandardItemModel,因为自定义委托控制数据输入。之后创建一个表视图来显示模型的内容,使用自定义委托进行编辑。
可以继承QStyledItemDelegate来实现自定义委托。
创建自定义委托需要实现

    // 创建自定义Widget
    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;

具体实现:

QWidget *C_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;
}

void C_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);
}

void C_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);
}

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

createEditor():当视图需要一个编辑器时,它会告诉委托为被修改的项提供一个编辑器控件。该函数提供了该功能,在这个函数,不需要为控件保留一个指针,因为视图会在不再需要该控件的时候进行删除。
setEditorData():委托将模型中的数据设置到控件中,控件需要判断类型,转换为合适的类型。
setModelData():编辑完控件后,调用此函数告诉委托将编辑好的数据设置到模型中。正常情况下,该函数完成后要发送closeEidt()信号告诉视图,视图对控件进行关闭和销毁。
updateEditorGeometry():告知委托设置控件的几何布局。

调用:

    QStandardItemModel *model = new QStandardItemModel(8, 4, this);

    QTableView *table = new QTableView(0);
    table->setModel(model);

    table->setItemDelegateForColumn(0, new C_SpinBoxDelegate);


    setCentralWidget(table);

显示如下:
image.png

3. 后续

编辑完成后,委托应该向其他组件提供关于编辑过程结果的提示,提供提示也有助于后续编辑操作。这个可以通过发出closeEditor()信号时使用合适的提示来实现。它们会被构造编辑控件时安装的默认QItemDelegate事件过滤器来捕获和处理的。

可以通过调整编辑控件的行为来使交互更加友好。在QItemDelegate提供的默认事件过滤器中,如果用户在编辑中按下回车键,委托会将值提交给模型并关闭控件。可以通过在控件上安装自己的事件过滤器来更改这种行为,并提供适合需求的编辑提示;例如,可以在发射closeEditor()信号时使用EditNextItem提示来实现编辑视图中的下一个项目。

另一种不需要使用事件过滤器的方法是提供自己的编辑控件,比如子类化QSpinBox。这种替代方法会对编辑控件有更多的控制,但需要编写额外的代码。如果需要自定义标准Qt编辑控件的行为,通常在委托中中安装事件过滤器更加便捷。

委托操作后可以不提供提示,但不提供提示的委托与应用程序集成程度较低,而且不如发出提示来支持常见编辑操作的委托好用。

4. 结论

委托是通过继承QStyledItemDelegate类,实现其相关方法,进而改变视图的默认操作。

咱们假设一下,可能项目需要,进行密码密文编辑,下拉框委托(QComboBox),颜色选择委托,图标委托等。那么每实现一个委托,就要单独继承一次QStyledItemDelegate类吗?当然没问题,但会不会但累赘了?

那有没有这样一种可能,创建一个类,并继承QStyledItemDelegate,然后将常用的委托全部实现,然后创建一些接口,通过这些接口对编辑器进行选择和初始化。
答案是肯定的。
思想 > 盲目操作。

文章来源:https://blog.csdn.net/MrHHHHHH/article/details/135686400
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。