前言
Qt版本:6.8.0
公共函数
1. 构造函数与析构函数
QStyledItemDelegate(QObject *parent = nullptr)
- 作用:创建样式化的项委托实例。
- 参数:
parent
: 父对象,用于内存管理(默认为nullptr
)。
- 示例:
QTableView tableView; QStyledItemDelegate *delegate = new QStyledItemDelegate(&tableView); tableView.setItemDelegate(delegate);
virtual ~QStyledItemDelegate()
- 作用:析构函数,清理资源。通常无需手动调用,由父对象自动管理。
2. 显示与数据转换
QString displayText(const QVariant &value, const QLocale &locale) const
- 作用:将数据
value
转换为显示的文本,考虑本地化 (locale
)。 - 参数:
value
: 模型中的数据(如整数、日期等)。locale
: 本地化设置(如日期格式、数字分隔符)。
- 返回值:格式化后的文本(
QString
)。 - 示例(重写以自定义显示):
QString MyDelegate::displayText(const QVariant &value, const QLocale &locale) const { if (value.type() == QVariant::Date) { return locale.toString(value.toDate(), "yyyy-MM-dd"); } return QStyledItemDelegate::displayText(value, locale); }
3. 编辑器工厂管理
QItemEditorFactory *itemEditorFactory() const
- 作用:获取当前使用的编辑器工厂。
- 返回值:指向
QItemEditorFactory
的指针。
void setItemEditorFactory(QItemEditorFactory *factory)
- 作用:设置自定义的编辑器工厂,用于创建特定数据类型的编辑器。
- 参数:
factory
: 新的编辑器工厂。
- 示例:
QItemEditorFactory *factory = new QItemEditorFactory; delegate->setItemEditorFactory(factory);
4. 核心重写函数
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
- 作用:创建用于编辑
index
数据的编辑器(如QLineEdit
、QSpinBox
)。 - 参数:
parent
: 编辑器的父控件。option
: 样式信息(如字体、颜色)。index
: 模型索引。
- 返回值:创建的编辑器控件指针。
- 示例(为整数类型创建
QSpinBox
):QWidget* MyDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { if (index.data().type() == QVariant::Int) { QSpinBox *editor = new QSpinBox(parent); editor->setRange(0, 100); return editor; } return QStyledItemDelegate::createEditor(parent, option, index); }
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
- 作用:绘制项的内容,使用当前样式确保外观一致。
- 参数:
painter
: 绘图工具。option
: 样式选项。index
: 模型索引。
- 示例(高亮特定项):
void MyDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QStyleOptionViewItem opt = option; initStyleOption(&opt, index); // 初始化默认样式 if (index.data().toInt() > 50) { opt.palette.setColor(QPalette::Text, Qt::red); } QStyledItemDelegate::paint(painter, opt, index); }
void setEditorData(QWidget *editor, const QModelIndex &index) const
- 作用:将模型数据加载到编辑器。
- 参数:
editor
: 创建的编辑器。index
: 模型索引。
- 示例(设置
QSpinBox
的值):void MyDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { int value = index.data().toInt(); QSpinBox *spinBox = static_cast<QSpinBox*>(editor); spinBox->setValue(value); }
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
- 作用:将编辑器数据保存回模型。
- 参数:
editor
: 编辑器控件。model
: 目标模型。index
: 模型索引。
- 示例(保存
QSpinBox
的值):void MyDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { QSpinBox *spinBox = static_cast<QSpinBox*>(editor); spinBox->interpretText(); // 确保获取最新值 model->setData(index, spinBox->value()); }
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
- 作用:返回项的建议大小。
- 返回值:
QSize
对象。 - 示例(根据内容调整大小):
QSize MyDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { QSize size = QStyledItemDelegate::sizeHint(option, index); QString text = index.data().toString(); if (text.length() > 10) { size.rwidth() += 50; // 增加宽度 } return size; }
`void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
- 作用:调整编辑器的位置和大小,使其覆盖项。
- 参数:
editor
: 编辑器控件。option
: 样式选项。index
: 模型索引。
- 示例:
void MyDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const { editor->setGeometry(option.rect); // 使编辑器覆盖项区域 }
virtual void destroyEditor(QWidget *editor, const QModelIndex &index) const
- 作用:销毁编辑器对象,当编辑完成或取消时调用。用于清理资源或断开信号槽连接。
- 参数:
editor
: 要销毁的编辑器控件指针。index
: 关联的模型索引(通常用于判断是否需要特殊清理)。
- 返回值:无。
- 示例(自定义清理逻辑):
class MyDelegate : public QStyledItemDelegate { public: void destroyEditor(QWidget *editor, const QModelIndex &index) const override { // 自定义清理逻辑(如断开信号槽) if (auto customEditor = qobject_cast<MyCustomEditor*>(editor)) { disconnect(customEditor, &MyCustomEditor::someSignal, nullptr, nullptr); } // 调用基类实现完成默认清理 QStyledItemDelegate::destroyEditor(editor, index); } };
virtual bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
- 作用:处理视图项上的事件(如鼠标点击、键盘事件)。返回
true
表示事件已处理。 - 参数:
event
: 事件对象(如QMouseEvent
、QKeyEvent
)。model
: 关联的数据模型。option
: 视图项的样式信息(如位置、字体)。index
: 事件触发的模型索引。
- 返回值:
bool
,true
表示事件被处理,阻止进一步传递。 - 示例(双击触发编辑或自定义操作):
bool MyDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) { if (event->type() == QEvent::MouseButtonDblClick) { // 触发编辑 return true; } else if (event->type() == QEvent::MouseButtonPress) { QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event); if (mouseEvent->button() == Qt::RightButton) { // 显示自定义右键菜单 showContextMenu(option.rect.topLeft(), index); return true; } } // 其他事件交由基类处理 return QStyledItemDelegate::editorEvent(event, model, option, index); }
virtual bool helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &index)
- 作用:处理帮助事件(如工具提示
QEvent::ToolTip
或状态栏提示)。返回true
表示事件已处理。 - 参数:
event
: 帮助事件对象(QHelpEvent
子类,如QToolTipEvent
)。view
: 触发事件的视图控件(如QTableView
)。option
: 视图项的样式信息。index
: 关联的模型索引。
- 返回值:
bool
,true
表示事件被处理。 - 示例(自定义工具提示内容):
bool MyDelegate::helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &index) { if (event->type() == QEvent::ToolTip) { // 获取数据 QString data = index.data(Qt::DisplayRole).toString(); // 自定义工具提示 QToolTip::showText(event->globalPos(), QString("详细信息: %1").arg(data), view, option.rect); return true; } return QStyledItemDelegate::helpEvent(event, view, option, index); }
总结
-
destroyEditor
- 用于清理自定义编辑器的资源。
- 必须调用基类实现以确保默认清理逻辑。
- 当编辑器需要释放非 Qt 管理的资源(如外部句柄)时重写
-
editorEvent
- 处理交互事件(如点击、双击、右键菜单)。
- 常用于实现自定义交互逻辑(如按钮、复选框)。
- 在表格项中嵌入交互控件(如按钮、开关)。
-
helpEvent
- 处理工具提示或其他帮助信息。
- 可动态生成提示内容(如显示额外数据)。
- 为复杂数据项提供动态提示(如预览图片、长文本)。
5. 保护函数
void initStyleOption(QStyleOptionViewItem *option, const QModelIndex &index) const
- 作用:初始化
option
的默认样式(如文本对齐、字体)。 - 示例(在自定义
paint
中调用):void MyDelegate::paint(...) { QStyleOptionViewItem opt; initStyleOption(&opt, index); // 先获取默认样式 // 修改 opt 后继续绘制 }
bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
- 作用:处理视图项上的事件(如鼠标点击)。
- 返回值:
true
表示事件已处理。 - 示例(双击启动编辑器):
bool MyDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) { if (event->type() == QEvent::MouseButtonDblClick) { // 触发编辑 return true; } return QStyledItemDelegate::editorEvent(event, model, option, index); }
bool eventFilter(QObject *editor, QEvent *event)
- 作用:过滤编辑器的事件(如回车键确认)。
- 示例(回车键提交数据):
bool MyDelegate::eventFilter(QObject *editor, QEvent *event) { if (event->type() == QEvent::KeyPress) { QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event); if (keyEvent->key() == Qt::Key_Enter) { emit commitData(editor); // 提交数据 return true; } } return QStyledItemDelegate::eventFilter(editor, event); }
信号
1. void closeEditor(QWidget *editor, QAbstractItemDelegate::EndEditHint hint = NoHint)
触发时机:
- 当用户完成对某个单元格的编辑(如按下Enter、Tab、Esc,或点击其他地方导致编辑结束)时,委托(delegate)会关闭编辑器控件,此时会发出该信号。 例如:你在QTableView 的某个单元格输入内容后,按下 Enter 键,编辑器关闭,这时会触发 closeEditor 信号。
参数解释:
QWidget *editor
:指向当前正在编辑的编辑器控件(如 QLineEdit、QComboBox 等)。QAbstractItemDelegate::EndEditHint hint
:指示编辑结束的原因或方式。常用的枚举值有:NoHint
:无特殊提示。EditNextItem
:请求编辑下一个项目。EditPreviousItem
:请求编辑上一个项目。SubmitModelCache
:提交模型缓存。RevertModelCache
:撤销模型缓存。
示例:
connect(delegate, &QAbstractItemDelegate::closeEditor, this, [](QWidget *editor, QAbstractItemDelegate::EndEditHint hint){
qDebug() << "Editor closed:" << editor << "Hint:" << hint;
});
2. void commitData(QWidget *editor)
触发时机:
-
当编辑器中的数据需要提交到模型时,会发出该信号。
通常在用户完成编辑(如按下 Enter、切换到其他单元格、编辑器失去焦点等)时触发。
例如:你在 QLineEdit 编辑单元格内容,按下 Enter 或切换到其他单元格,编辑器会将数据提交到模型,并发出commitData 信号。
参数解释:
QWidget *editor
:指向当前正在编辑的编辑器控件。这个信号通常在编辑器中的数据需要提交到模型时发出。
示例:
connect(delegate, &QAbstractItemDelegate::commitData, this, [](QWidget *editor){
qDebug() << "Commit data from editor:" << editor;
});
3. void sizeHintChanged(const QModelIndex &index)
触发时机:
-
当某个项的推荐显示尺寸(sizeHint)发生变化时,委托会发出该信号,通知视图重新布局。
例如:你自定义的委托在某些条件下改变了单元格的高度或宽度(如内容变多、字体变大),需要通知视图更新显示时,会触发该信号。
参数解释:
const QModelIndex &index
:指向模型中发生尺寸变化的项的索引。这个信号在某个项的 sizeHint(推荐显示尺寸)发生变化时发出,通常用于通知视图重新布局。
示例:
connect(delegate, &QAbstractItemDelegate::sizeHintChanged, this, [](const QModelIndex &index){
qDebug() << "Size hint changed for index:" << index;
});
示例
示例 1:整数输入委托(使用 QSpinBox
)
功能:为整数类型的数据提供带有范围限制的 QSpinBox
编辑器。
class IntSpinBoxDelegate : public QStyledItemDelegate {
public:
IntSpinBoxDelegate(int min, int max, QObject *parent = nullptr)
: QStyledItemDelegate(parent), m_min(min), m_max(max) {}
// 创建 QSpinBox 编辑器
QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option,
const QModelIndex &index) const override {
QSpinBox *editor = new QSpinBox(parent);
editor->setRange(m_min, m_max);
editor->setFrame(false); // 无边框
return editor;
}
// 将模型数据加载到编辑器
void setEditorData(QWidget *editor, const QModelIndex &index) const override {
int value = index.data(Qt::EditRole).toInt();
QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
spinBox->setValue(value);
}
// 将编辑器数据保存回模型
void setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const override {
QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
spinBox->interpretText(); // 确保获取最新值
model->setData(index, spinBox->value(), Qt::EditRole);
}
private:
int m_min, m_max;
};
// 使用方式
QTableView tableView;
tableView.setItemDelegate(new IntSpinBoxDelegate(0, 100, &tableView));
示例 2:日期选择委托(使用 QDateEdit
)
功能:为日期类型的数据提供日历下拉编辑器。
class DateEditDelegate : public QStyledItemDelegate {
public:
DateEditDelegate(QObject *parent = nullptr) : QStyledItemDelegate(parent) {}
QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option,
const QModelIndex &index) const override {
QDateEdit *editor = new QDateEdit(parent);
editor->setCalendarPopup(true); // 启用日历弹窗
editor->setDisplayFormat("yyyy-MM-dd");
return editor;
}
void setEditorData(QWidget *editor, const QModelIndex &index) const override {
QDate date = index.data(Qt::EditRole).toDate();
QDateEdit *dateEdit = static_cast<QDateEdit*>(editor);
dateEdit->setDate(date);
}
void setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const override {
QDateEdit *dateEdit = static_cast<QDateEdit*>(editor);
model->setData(index, dateEdit->date(), Qt::EditRole);
}
// 格式化显示文本
QString displayText(const QVariant &value, const QLocale &locale) const override {
return value.toDate().toString("yyyy-MM-dd");
}
};
// 使用方式
tableView.setItemDelegateForColumn(1, new DateEditDelegate(&tableView));
示例 3:富文本(HTML)渲染委托
功能:显示带有 HTML 格式的文本(如加粗、颜色)。
class RichTextDelegate : public QStyledItemDelegate {
public:
using QStyledItemDelegate::QStyledItemDelegate;
// 自定义绘制
void paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const override {
QStyleOptionViewItem opt = option;
initStyleOption(&opt, index);
// 使用 QTextDocument 渲染 HTML
QTextDocument doc;
doc.setHtml(opt.text);
doc.setDefaultFont(opt.font);
painter->save();
painter->translate(opt.rect.topLeft());
doc.drawContents(painter);
painter->restore();
}
// 调整项大小以适应 HTML 内容
QSize sizeHint(const QStyleOptionViewItem &option,
const QModelIndex &index) const override {
QTextDocument doc;
doc.setHtml(index.data().toString());
doc.setDefaultFont(option.font);
return QSize(doc.idealWidth(), doc.size().height());
}
};
// 使用方式
tableView.setItemDelegate(new RichTextDelegate(&tableView));
示例 4:按钮委托(点击触发动作)
功能:在项中绘制按钮,点击后执行自定义操作。
class ButtonDelegate : public QStyledItemDelegate {
Q_OBJECT
public:
using QStyledItemDelegate::QStyledItemDelegate;
// 绘制按钮
void paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const override {
QStyleOptionButton button;
button.rect = option.rect.adjusted(2, 2, -2, -2);
button.text = "Action";
button.state = QStyle::State_Enabled;
QApplication::style()->drawControl(QStyle::CE_PushButton, &button, painter);
}
// 处理点击事件
bool editorEvent(QEvent *event, QAbstractItemModel *model,
const QStyleOptionViewItem &option,
const QModelIndex &index) override {
if (event->type() == QEvent::MouseButtonRelease) {
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
if (option.rect.contains(mouseEvent->pos())) {
emit buttonClicked(index);
return true;
}
}
return false;
}
signals:
void buttonClicked(const QModelIndex &index);
};
// 使用方式(连接信号)
ButtonDelegate *delegate = new ButtonDelegate(&tableView);
tableView.setItemDelegateForRow(0, delegate);
connect(delegate, &ButtonDelegate::buttonClicked, [](const QModelIndex &index) {
qDebug() << "Button clicked at row:" << index.row();
});
示例 5:进度条委托(使用 QStyle
绘制)
功能:将数值显示为进度条样式。
class ProgressBarDelegate : public QStyledItemDelegate {
public:
using QStyledItemDelegate::QStyledItemDelegate;
void paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const override {
// 获取数据值(假设范围 0-100)
int value = index.data().toInt();
value = qBound(0, value, 100);
// 绘制进度条
QStyleOptionProgressBar progressBarOption;
progressBarOption.rect = option.rect.adjusted(2, 2, -2, -2);
progressBarOption.minimum = 0;
progressBarOption.maximum = 100;
progressBarOption.progress = value;
progressBarOption.text = QString("%1%").arg(value);
progressBarOption.textVisible = true;
QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption, painter);
}
};
// 使用方式
tableView.setItemDelegateForColumn(2, new ProgressBarDelegate(&tableView));
示例 6:自定义图标+文本委托
功能:在项左侧显示图标,右侧显示文本。
class IconTextDelegate : public QStyledItemDelegate {
public:
IconTextDelegate(const QIcon &icon, QObject *parent = nullptr)
: QStyledItemDelegate(parent), m_icon(icon) {}
void paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const override {
QStyleOptionViewItem opt = option;
initStyleOption(&opt, index);
// 绘制图标
QRect iconRect = opt.rect;
iconRect.setWidth(16); // 图标宽度
m_icon.paint(painter, iconRect, Qt::AlignLeft | Qt::AlignVCenter);
// 绘制文本(向右偏移图标宽度)
QRect textRect = opt.rect.adjusted(20, 0, 0, 0);
painter->drawText(textRect, opt.displayAlignment, opt.text);
}
private:
QIcon m_icon;
};
// 使用方式
tableView.setItemDelegate(new IconTextDelegate(QIcon(":/icon.png"), &tableView));
总结
- 核心方法:通过重写
paint
、createEditor
、setEditorData
和setModelData
实现不同效果。 - 交互处理:使用
editorEvent
捕获点击或键盘事件。 - 性能优化:复杂绘制(如 HTML)需注意性能,避免频繁创建
QTextDocument
。 - 信号传递:通过自定义信号(如
buttonClicked
)将委托事件传递到业务逻辑。