QT模型/视图:自定义代理类型

简介

在模型/视图结构中,代理的作用就是在视图组件进入编辑状态编辑某个项时,提供一个临时的编辑器用于数据编辑,编辑完成后再把数据提交给数据模型。例如,在 QTableView 组件上双击一个单元格时,代理会提供一个临时的编辑器,默认是 QLineEdit 编辑框,在这个编辑框里修改项 的文字,按 Enter 键或焦点移动到其他单元格时完成编辑,编辑框内的文字会保存到数据模型。

自定义代理类需要从 QStyledItemDelegate 类继承,创建自定义代理类的实 例后,再将其设置为整个视图组件或视图组件的某行或某列的代理,以替代默认代理的功能。

QAbstractItemView 类定义了设置自定义代理的 3 个函数,分别是整个视图组件的代理、为某一列设置自定义代理、为某一行设置自定义代理,函数定义如下:

void setItemDelegate(QAbstractItemDelegate *delegate)

void setItemDelegateForColumn(int column, QAbstractItemDelegate *delegate)

void setItemDelegateForRow(int row, QAbstractItemDelegate *delegate)

QStyledItemDelegate 是视图组件使用的默认代理类,一般使用 QStyledItemDelegate 作为自定

义代理类的父类。要自定义一个代理类,必须重新实现 QStyledItemDelegate 中定义的 4 个虚函数。 这 4 个函数是由模型/视图系统自动调用的。

1.函数 createEditor()

函数 createEditor()可创建用于编辑模型数据的界面组件,称为代理编辑器,例如 QSpinBox

组件,或 QComboBox 组件。其函数原型定义如下:
QWidget *QStyledItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index)

其中,parent 是要创建的组件的父组件,一般就是窗口对象;option 是项的一些显示选项,是

QStyleOptionViewItem 类型的,包含字体、对齐方式、背景色等属性;index 是项在数据模型中的

模型索引,通过 index->model()可以获取项所属数据模型的对象指针。
2.函数 setEditorData()

函数 setEditorData()的功能是从数据模型获取项的某个角色(一般是 EditRole 角色)的数据, 然后将其设置为代理编辑器上显示的数据。其函数原型定义如下:

void QStyledItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index)
参数 editor 就是前面用函数 createEditor()创建的代理编辑器,通过 index->model()可以获取项所属数据模型的对象指针,从而获取项的数据,然后将其显示在代理编辑器上。

3.函数 setModelData()
完成对当前单元格的编辑,例如输入焦点移到其他单元格时,系统会自动调用函数 setModelData(),

其功能是将代理编辑器里的输入数据保存到数据模型的项里。其函数原型定义如下:

void QStyledItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,

const QModelIndex &index)

其中,editor 是代理编辑器,model 是数据模型,index 是所编辑的项在模型中的模型索引。

4.函数 updateEditorGeometry()

视图组件在界面上显示代理编辑器时,需要调用 updateEditorGeometry()函数为组件设置合适 的大小,例如在一个单元格里显示一个 QSpinBox 代理编辑器时,一般将其设置为单元格的大小。

其函数原型定义如下:

void QStyledItemDelegate::updateEditorGeometry(QWidget *editor,

const QStyleOptionViewItem &option, const QModelIndex &index)

其中,变量 option->rect 是 QRect 类型,表示代理编辑器的建议大小。一般将代理编辑器大小设 置为建议大小即可,即用下面的一行代码:

editor->setGeometry(option.rect);

案例:自定义代理类TFloatSpinDelegate

在QT Creator中新建C++类,并设置基类为 QStyledItemDelegate,要勾选 Add Q_OBJECT 复选框,因为要在 TFloatSpinDelegate 类中插入 Q_OBJECT 宏。

然后实现基类中的虚函数即可。

cpp 复制代码
QWidget *TFloatSpinDelegate::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->setMaximum(20000);
    editor->setDecimals(2);     //显示两位小数

    return editor;
}

void TFloatSpinDelegate::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 TFloatSpinDelegate::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 TFloatSpinDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,
                                              const QModelIndex &index) const
{
    Q_UNUSED(index);
    editor->setGeometry(option.rect);
}

案例:自定义代理类TComboBoxDelegate

同样创建一个新的C++类,并实现基类的4个虚函数

cpp 复制代码
void TComboBoxDelegate::setItems(QStringList items, bool editable)
{
    m_itemList=items;
    m_editable=editable;
}

QWidget *TComboBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option,
                                         const QModelIndex &index) const
{
    Q_UNUSED(option);
    Q_UNUSED(index);

    QComboBox *editor = new QComboBox(parent);        //自定义的组件
    editor->setEditable(m_editable);	//是否可编辑
    for (int i=0;i<m_itemList.count();i++)   //从字符串列表初始下拉列表
        editor->addItem(m_itemList.at(i));
    return editor;
}

void TComboBoxDelegate::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 TComboBoxDelegate::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 TComboBoxDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,
                                             const QModelIndex &index) const
{
    Q_UNUSED(index);
    editor->setGeometry(option.rect);
}

自定义函数 setItems()用于设置变量 m_itemList 和 m_editable 的值,在函数 createEditor()里动态

创建 QComboBox 组件时,用于设置下拉列表的内容以及是否可以编辑。

使用自定义代理

cpp 复制代码
    m_model = new QStandardItemModel(2,FixedColumnCount,this); //创建数据模型
    m_selection = new QItemSelectionModel(m_model, this);           //创建选择模型


    //为tableView设置数据模型
    ui->tableView->setModel(m_model);  //设置数据模型
    ui->tableView->setSelectionModel(m_selection); //设置选择模型
    ui->tableView->setSelectionMode(QAbstractItemView::ExtendedSelection);
    ui->tableView->setSelectionBehavior(QAbstractItemView::SelectItems);

    ///注意设置的这些代理组件只有在编辑时才有效果
    intSpinDelegate= new TSpinBoxDelegate(this);      ///setItemDelegate是整个视图组件的代理
    ui->tableView->setItemDelegateForColumn(0, intSpinDelegate);    //测深   setItemDelegateForColumn为某一列的代理

    floatSpinDelegate = new TFloatSpinDelegate(this);
    ui->tableView->setItemDelegateForColumn(1, floatSpinDelegate);  //垂深
    ui->tableView->setItemDelegateForColumn(2, floatSpinDelegate);  //方位
    ui->tableView->setItemDelegateForColumn(3, floatSpinDelegate);  //总位移

    comboDelegate = new TComboBoxDelegate(this);
    QStringList strList;
    strList<<"优"<<"良"<<"一般"<<"不合格";
    comboDelegate->setItems(strList,false);
    ui->tableView->setItemDelegateForColumn(4, comboDelegate);   //固井质量

这样增加了自定义代理功能后,在编辑"测深"列时,会在单元格的位置出现一个 SpinBox 用于输入整数;在编辑第二到四列的浮点数时,会出现一个 DoubleSpinBox 用于输入浮点数;在 编辑"固井质量"列时,会出现一个下拉列表框用于从下拉列表中选择一个字符串。

相关推荐
凌盛羽1 小时前
C#对Excel表csv文件的读写操作
开发语言·windows·物联网·microsoft·c#·excel
VBA63371 小时前
VBA高级应用30例应用在Excel中的ListObject对象:向表中添加注释
开发语言
Dontla1 小时前
Rust字节数组(Byte Array)Rust u8、Vec<u8>、数组切片、向量切片、字符串转字节数组转字符串、&[u8]类型:字节数组引用
开发语言·rust
走在考研路上3 小时前
Python错误处理
开发语言·python
数据小爬虫@3 小时前
Python爬虫:如何优雅地“偷窥”商品详情
开发语言·爬虫·python
CV大法好3 小时前
刘铁猛p3 C# 控制台程序引用System.Windows.Forms报错,无法引用程序集 解决方法
开发语言·c#
Days20503 小时前
uniapp小程序增加加载功能
开发语言·前端·javascript
朱小勇本勇4 小时前
Qt实现控件拖曳
开发语言·数据库·qt
片片叶4 小时前
C++(十四)
开发语言·c++
dengjiayue4 小时前
golang实现简单的reids服务2
开发语言·golang