前言
前些阵子在写一个小demo时遇到一个问题,如何在QTableView中添加控件,也研究了一会,确实可以使用一些方法进行添加;但是控件一直都是显示在单元格上的,并不是我想要的效果,如下图(在单元格中添加QComboBox):
控件虽然添加到单元格中了,但是其显示得硬邦邦的,这并不好;于是乎,经过九牛二虎之力,发现使用委托可以实现我需要的那种效果,如下图:
其默认显示是和其他单元格一样的,但是只要我双击后,添加到单元格里面的QComboBox控件才进行显示。
定义
要想达到这种效果,首先必须得自定义类,然后继承QItemDelegate,最后重写其里面的一些方法即可。
需要包含头文件:#include <QItemDelegate>
-
继承于QItemDelegate
class WidgetDelegate : public QItemDelegate { // ... }
-
重写以下四个方法
// 创建编辑器 virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override; // 设置编辑器数据 virtual void setEditorData(QWidget *editor, const QModelIndex &index) const override; // 更新编辑器集合属性 virtual void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override; // 设置模型数据 virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override;
每个方法都有其独特的作用;当然QItemDelegate类也还有许多其他方法可以进行重写实现,有兴趣的小伙伴可以去参考QT帮助文档。
-
实现方法体
(1). 创建编辑器 createEditor
此方法的作用:创建自己需要的控件,进行返回。// 创建编辑器 QWidget *WidgetDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { // 创建自己需要的控件进行返回 QComboBox *editor = new QComboBox(parent); return editor; }
(2). 设置编辑器数据 setEditorData
此方法的作用:为创建的控件设值。// 设置编辑器数据 void WidgetDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { // 将参数editor转换为对应创建的控件,再进行数据初始设置就行 QComboBox *cob = static_cast<QComboBox *>(editor); cob->addItems(m_comboBoxList); }
(3). 更新编辑器集合属性 updateEditorGeometry
此方法的作用:设置控件的属性,例如将其设置为矩形、圆形等。// 更新编辑器集合属性 void WidgetDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const { // 将编辑器设置为矩形属性 editor->setGeometry(option.rect); }
(4). 设置模型数据 setModelData
此方法的作用:设置控件对应单元格中显示的数据。// 设置模型数据 void WidgetDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { QComboBox *comboBox = static_cast<QComboBox *>(editor); // 类型转换 // 模型(单元格)显示的数据 model->setData(index, comboBox->currentText()); }
好了,到了这里,说明前期准备工作已经做得差不多了,接下来就可以去使用这个类了。
当然,也还可以定义几个自己的方法来对数据的管理。
#pragma once
#include <QItemDelegate>
class WidgetDelegate : public QItemDelegate {
Q_OBJECT
public:
WidgetDelegate(QItemDelegate *parent = nullptr);
WidgetDelegate(QStringList list, QItemDelegate *parent = nullptr);
~WidgetDelegate();
// ...
/*****根据项目需求增添辅佐函数*****/
// 获取索引数据
QString getCurrentComboBoxData(int index);
// 插入
void insertCoBData(QString str);
// 删除
void removeCobData(QString str);
private:
// 存储QComBoBox的数据
QStringList m_comboBoxList;
};
例如,我这里定义了一个私有字符串链表,用来存储QComboBox的数据;然后再定义了三个方法,用于获取、插入和删除QComboBox中的数据。
还定义了两个构造函数,一个默认定义即可,还有一个需要指定参数定义。
三个自定义方法体实现如下:
// 获取索引处的数据返回
QString WidgetDelegate::getCurrentComboBoxData(int index) {
return this->m_comboBoxList.at(index);
}
// 插入数据
void WidgetDelegate::insertCoBData(QString str) {
this->m_comboBoxList.append(str);
}
// 移除数据
void WidgetDelegate::removeCobData(QString str) {
// 找到链表中与参数相同的字符串,然后将其移除掉
for (int i = 0; i < this->m_comboBoxList.size(); i++) {
if (str == this->m_comboBoxList[i]) {
this->m_comboBoxList.removeAt(i);
return;
}
}
}
可以根据自己的项目需求进行编写。
使用
#include "WidgetDelegate"
#include <QTableView>
QStringList list;
list << "A" << "B" << "C";
// 创建时指定数据传入
WidgetDelegate *m_cBoxDelegate = new WidgetDelegate(list);
QTableView *tableView = new QTableView;
/*************************/
// 将某一列单元格设置为该委托
tableView->setItemDelegateForColumn(m_cBoxDelegate);
// 将某一行单元格设置为该委托
tableView->setItemDelegateForRow(m_cBoxDelegate);
// 将全部单元格设置为该委托
tableView->setItemDelegate(m_cBoxDelegate);
/*********************************/
自定义委托类代码
WidgetDelegate.h
#pragma once
#include <QItemDelegate>
class WidgetDelegate : public QItemDelegate {
Q_OBJECT
public:
WidgetDelegate(QItemDelegate *parent = nullptr);
WidgetDelegate(QStringList list, QItemDelegate *parent = nullptr);
~WidgetDelegate();
// 创建编辑器
virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
// 设置编辑器数据
virtual void setEditorData(QWidget *editor, const QModelIndex &index) const override;
// 更新编辑器集合属性
virtual void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
// 设置模型数据
virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override;
/*****根据项目需求增添辅佐函数*****/
// 获取索引数据
QString getCurrentComboBoxData(int index);
// 插入
void insertCoBData(QString str);
// 删除
void removeCobData(QString str);
private:
QStringList m_comboBoxList;
};
WidgetDelegate.cpp
#include "WidgetDelegate.h"
#include <QComboBox>
WidgetDelegate::WidgetDelegate(QItemDelegate *parent) : QItemDelegate(parent) {
this->m_comboBoxList << "";
}
WidgetDelegate::WidgetDelegate(QStringList list, QItemDelegate *parent) :QItemDelegate(parent) {
this->m_comboBoxList = list;
}
WidgetDelegate::~WidgetDelegate() {
}
// 创建编辑器
QWidget *WidgetDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const {
// 创建自己需要的控件进行返回
QComboBox *editor = new QComboBox(parent);
return editor;
}
// 设置编辑器数据
void WidgetDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const {
// 将参数editor转换为对应创建的控件,再进行数据初始设置就行
QComboBox *cob = static_cast<QComboBox *>(editor);
cob->addItems(m_comboBoxList);
}
// 更新编辑器集合属性
void WidgetDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const {
// 将编辑器设置为矩形属性
editor->setGeometry(option.rect);
}
// 设置模型数据
void WidgetDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const {
QComboBox *comboBox = static_cast<QComboBox *>(editor); // 类型转换
// 模型(单元格)显示的数据
model->setData(index, comboBox->currentText());
}
// 获取索引处的数据返回
QString WidgetDelegate::getCurrentComboBoxData(int index) {
return this->m_comboBoxList.at(index);
}
// 插入数据
void WidgetDelegate::insertCoBData(QString str) {
this->m_comboBoxList.append(str);
}
// 移除数据
void WidgetDelegate::removeCobData(QString str) {
for (int i = 0; i < this->m_comboBoxList.size(); i++) {
if (str == this->m_comboBoxList[i]) {
this->m_comboBoxList.removeAt(i);
return;
}
}
}
总结:
使用此方式进行单元格添加控件,对于管理上来说,还是蛮方便的,也理清了许多思路;当然除了可以添加QComboBox控件外,也还可以添加QSpinBox等控件也都是完全没问题的。
值得注意的是,不建议使用该方式进行添加QCheckBox,因为其是会自动隐藏的,需要双击单元格才会显示,所以不合适。
看到此篇博客的朋友如果也有此方面的需求,可以直接创建两个文件(.h和.cpp文件),将上面的代码赋值进去就可以直接使用该类了。