忧郁的大能猫
好奇的探索者,理性的思考者,踏实的行动者。
Table of Contents:
在 Qt 中,自定义委托(Delegate)是控制视图项(Item)呈现和行为的强大工具。除了设置高度外,自定义委托还可以实现以下功能:
void WaveItemDelegate::paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const {
// 保存原始状态
painter->save();
// 设置背景
if (option.state & QStyle::State_Selected) {
painter->fillRect(option.rect, QColor("#e6f7ff")); // 选中状态
} else if (option.state & QStyle::State_MouseOver) {
painter->fillRect(option.rect, QColor("#f5f5f5")); // 悬停状态
} else {
painter->fillRect(option.rect, Qt::white); // 默认状态
}
// 绘制边框
painter->setPen(QColor("#e0e0e0"));
painter->drawRect(option.rect.adjusted(0, 0, -1, -1));
// 获取数据
MuItemData data = index.data(Qt::UserRole+1).value<MuItemData>();
// 绘制文件名
painter->setPen(Qt::black);
QFont font = painter->font();
font.setBold(true);
painter->setFont(font);
painter->drawText(option.rect.adjusted(10, 5, -10, -30),
Qt::AlignLeft | Qt::AlignTop,
data.filename);
// 绘制波形预览
painter->setPen(QColor("#1890ff"));
QRect waveRect = option.rect.adjusted(10, 30, -10, -10);
drawWavePreview(painter, waveRect, data.waveData);
// 绘制时长信息
painter->setPen(Qt::darkGray);
painter->setFont(QFont("Arial", 8));
painter->drawText(waveRect, Qt::AlignRight | Qt::AlignBottom,
formatDuration(data.duration));
// 恢复原始状态
painter->restore();
}bool WaveItemDelegate::editorEvent(QEvent *event,
QAbstractItemModel *model,
const QStyleOptionViewItem &option,
const QModelIndex &index) {
if (event->type() == QEvent::MouseButtonPress) {
QMouseEvent *me = static_cast<QMouseEvent*>(event);
if (me->button() == Qt::LeftButton) {
// 检测是否点击了删除按钮区域
QRect deleteButton = calculateDeleteButtonRect(option.rect);
if (deleteButton.contains(me->pos())) {
emit deleteRequested(index);
return true;
}
}
}
return QStyledItemDelegate::editorEvent(event, model, option, index);
}// 创建自定义编辑器
QWidget* WaveItemDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index) const {
WaveItemEditor *editor = new WaveItemEditor(parent);
// 设置编辑器属性...
return editor;
}
// 设置编辑器数据
void WaveItemDelegate::setEditorData(QWidget *editor,
const QModelIndex &index) const {
WaveItemEditor *customEditor = static_cast<WaveItemEditor*>(editor);
MuItemData data = index.data(Qt::UserRole+1).value<MuItemData>();
customEditor->setData(data);
}
// 保存数据到模型
void WaveItemDelegate::setModelData(QWidget *editor,
QAbstractItemModel *model,
const QModelIndex &index) const {
WaveItemEditor *customEditor = static_cast<WaveItemEditor*>(editor);
MuItemData newData = customEditor->getData();
model->setData(index, QVariant::fromValue(newData), Qt::UserRole+1);
}void WaveItemDelegate::paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const {
// ...
// 绘制加载动画
if (data.isLoading) {
int progress = calculateProgress();
drawLoadingAnimation(painter, option.rect, progress);
}
// 绘制交互反馈
if (m_hoverIndex == index) {
drawHoverEffect(painter, option.rect);
}
}QSize WaveItemDelegate::sizeHint(const QStyleOptionViewItem &option,
const QModelIndex &index) const {
MuItemData data = index.data(Qt::UserRole+1).value<MuItemData>();
// 计算所需高度
int height = 60; // 基础高度
if (data.hasTags) height += 20; // 如果有标签额外高度
if (data.hasPreview) height += 30; // 如果有预览额外高度
return QSize(option.rect.width(), height);
}void WaveItemDelegate::paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const {
// ...
// 根据状态显示不同图标
if (data.status == MuItemData::Processing) {
drawIcon(painter, option.rect.topRight(), QIcon(":/processing.png"));
} else if (data.status == MuItemData::Completed) {
drawIcon(painter, option.rect.topRight(), QIcon(":/completed.png"));
} else if (data.status == MuItemData::Error) {
drawIcon(painter, option.rect.topRight(), QIcon(":/error.png"));
}
}void WaveItemDelegate::drawWavePreview(QPainter *painter,
const QRect &rect,
const QVector<float> &waveData) const {
if (waveData.isEmpty()) return;
painter->save();
QPainterPath path;
path.moveTo(rect.left(), rect.center().y());
float dx = static_cast<float>(rect.width()) / (waveData.size() - 1);
for (int i = 0; i < waveData.size(); ++i) {
float y = rect.center().y() - waveData[i] * rect.height() / 2;
path.lineTo(rect.left() + i * dx, y);
}
painter->setPen(QPen(QColor("#1890ff"), 1.5));
painter->drawPath(path);
painter->restore();
}// 在委托类中添加缓存
mutable QCache<QString, QPixmap> m_iconCache;
void WaveItemDelegate::drawIcon(QPainter *painter,
const QPoint &pos,
const QString &iconPath) const {
// 检查缓存
if (!m_iconCache.contains(iconPath)) {
QPixmap icon(iconPath);
icon = icon.scaled(16, 16, Qt::KeepAspectRatio, Qt::SmoothTransformation);
m_iconCache.insert(iconPath, new QPixmap(icon));
}
painter->drawPixmap(pos, *m_iconCache.object(iconPath));
}void WaveItemDelegate::paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const {
// ...
// 绘制播放按钮
if (data.canPlay) {
QRect playRect = calculatePlayButtonRect(option.rect);
drawPlayButton(painter, playRect, data.isPlaying);
}
// 绘制音量控制
if (data.showVolumeControl) {
QRect volumeRect = calculateVolumeRect(option.rect);
drawVolumeControl(painter, volumeRect, data.volume);
}
}void WaveItemDelegate::paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const {
// ...
// 根据主题设置颜色
QColor textColor = m_theme == DarkTheme ? Qt::white : Qt::black;
QColor bgColor = m_theme == DarkTheme ? QColor("#333") : Qt::white;
// 绘制特殊状态效果
if (data.isModified) {
painter->setPen(QPen(Qt::yellow, 2));
painter->drawRect(option.rect.adjusted(1, 1, -1, -1));
}
}class AdvancedWaveDelegate : public QStyledItemDelegate {
Q_OBJECT
public:
explicit AdvancedWaveDelegate(QObject *parent = nullptr);
QSize sizeHint(const QStyleOptionViewItem &option,
const QModelIndex &index) const override;
void paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const override;
bool editorEvent(QEvent *event,
QAbstractItemModel *model,
const QStyleOptionViewItem &option,
const QModelIndex &index) override;
signals:
void playClicked(const QModelIndex &index);
void deleteClicked(const QModelIndex &index);
void volumeChanged(const QModelIndex &index, int volume);
private:
void drawWavePreview(QPainter *painter, const QRect &rect,
const QVector<float> &waveData) const;
void drawPlayButton(QPainter *painter, const QRect &rect,
bool isPlaying) const;
void drawVolumeControl(QPainter *painter, const QRect &rect,
int volume) const;
QRect playButtonRect(const QRect &itemRect) const;
QRect deleteButtonRect(const QRect &itemRect) const;
QRect volumeControlRect(const QRect &itemRect) const;
mutable QModelIndex m_hoverIndex;
int m_activeVolumeControl = -1; // 当前激活的音量控制项
};
// 实现略... 包含上述所有功能| 场景 | 推荐方法 |
|---|---|
| 简单高度调整 | 使用sizeHint() |
| 复杂视觉效果 | 完全重写paint() |
| 项内交互 | 实现editorEvent() |
| 自定义编辑 | 实现createEditor()系列方法 |
| 性能敏感场景 | 使用缓存和部分重绘优化 |
paint()中进行复杂计算自定义委托是 Qt 视图系统中功能最强大的组件之一,通过合理利用其能力,可以实现几乎任何类型的列表/表格项呈现效果和交互行为。