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 用于输入浮点数;在 编辑"固井质量"列时,会出现一个下拉列表框用于从下拉列表中选择一个字符串。

相关推荐
网络风云18 分钟前
golang中的包管理-下--详解
开发语言·后端·golang
小唐C++36 分钟前
C++小病毒-1.0勒索
开发语言·c++·vscode·python·算法·c#·编辑器
S-X-S41 分钟前
集成Sleuth实现链路追踪
java·开发语言·链路追踪
北 染 星 辰1 小时前
Python网络自动化运维---用户交互模块
开发语言·python·自动化
佳心饼干-1 小时前
数据结构-栈
开发语言·数据结构
我们的五年1 小时前
【C语言学习】:C语言补充:转义字符,<<,>>操作符,IDE
c语言·开发语言·后端·学习
灯火不休ᝰ1 小时前
[java] java基础-字符串篇
java·开发语言·string
励志去大厂的菜鸟2 小时前
系统相关类——java.lang.Math (三)(案例详细拆解小白友好)
java·服务器·开发语言·深度学习·学习方法
w(゚Д゚)w吓洗宝宝了2 小时前
单例模式 - 单例模式的实现与应用
开发语言·javascript·单例模式
siy23332 小时前
【c语言日寄】Vs调试——新手向
c语言·开发语言·学习·算法