使用 QStyledItemDelegate 绘制 QTreeView 项目
Drawing QTreeView items with QStyledItemDelegate
我已经根据 Qt 示例列表中的 Simple Tree Model Example
创建了一个项目并编辑了它的模型,以便也可以检查一些项目;这是它的样子:
我希望将一些项目稍微向左移动。所以我通过派生 QStyledItemDelegate
创建了一个委托并像这样重新实现 QStyledItemDelegate::paint
:
void TreeItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if (index.column() == 0) {
TreeItem *childItem = static_cast<TreeItem*>(index.internalPointer());
if (childItem->type() == TreeItem::Type::Checkable) {
QStyleOptionViewItem opt = option;
QStyledItemDelegate::initStyleOption(&opt, index);
const int desiredThreshold = 10;
opt.rect.setX(opt.rect.x() - desiredThreshold);
option.widget->style()->drawControl(QStyle::CE_ItemViewItem, &opt, painter, option.widget);
return;
}
}
return QStyledItemDelegate::paint(painter, option, index);
}
这样 TreeItem::Type::Checkable
类型的项目将根据 desiredThreshold
常量的值(在本例中为 10 像素)绘制到左侧。
到目前为止一切顺利;一切正常,绘图正确完成。然而...
问题是虽然项目被稍微向左绘制(这没问题),但鼠标事件仍然有效,就好像项目根本没有移动一样;它是这样工作的:
是否可以告诉代表整个项目稍微向左绘制,以便当我单击复选框(也与整个项目一起移动)时模型会正确更新?
原因
您可以更改 ItemViewItem
在屏幕上的呈现方式,但不会更改它对用户操作的响应方式。
解决方案
我建议你重新实现 QStyledItemDelegate::editorEvent; in order to adjust the position of the QRect
returned by QStyle::subElementRect when called with QStyle::SE_ItemViewItemCheckIndicator 作为参数。
例子
考虑以下步骤:
- 在你的
TreeItemDelegate
class 中添加一个 public editorEvent
方法
- 将
QStyledItemDelegate::editorEvent
的 default implementation 复制到您的代码中
通过改变
避免调用QStyledItemDelegate
的私有方法
const QWidget *widget = QStyledItemDelegatePrivate::widget(option);
QStyle *style = widget ? widget->style() : QApplication::style();
到
QStyle *style = option.widget->style();
通过改变
调整checkRect
的位置
QRect checkRect = style->subElementRect(QStyle::SE_ItemViewItemCheckIndicator, &viewOpt, widget);
到
QRect checkRect = style->subElementRect(QStyle::SE_ItemViewItemCheckIndicator, &viewOpt, option.widget).adjusted(-10, 0, -10, 0);
我已经根据 Qt 示例列表中的 Simple Tree Model Example
创建了一个项目并编辑了它的模型,以便也可以检查一些项目;这是它的样子:
我希望将一些项目稍微向左移动。所以我通过派生 QStyledItemDelegate
创建了一个委托并像这样重新实现 QStyledItemDelegate::paint
:
void TreeItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if (index.column() == 0) {
TreeItem *childItem = static_cast<TreeItem*>(index.internalPointer());
if (childItem->type() == TreeItem::Type::Checkable) {
QStyleOptionViewItem opt = option;
QStyledItemDelegate::initStyleOption(&opt, index);
const int desiredThreshold = 10;
opt.rect.setX(opt.rect.x() - desiredThreshold);
option.widget->style()->drawControl(QStyle::CE_ItemViewItem, &opt, painter, option.widget);
return;
}
}
return QStyledItemDelegate::paint(painter, option, index);
}
这样 TreeItem::Type::Checkable
类型的项目将根据 desiredThreshold
常量的值(在本例中为 10 像素)绘制到左侧。
到目前为止一切顺利;一切正常,绘图正确完成。然而...
问题是虽然项目被稍微向左绘制(这没问题),但鼠标事件仍然有效,就好像项目根本没有移动一样;它是这样工作的:
是否可以告诉代表整个项目稍微向左绘制,以便当我单击复选框(也与整个项目一起移动)时模型会正确更新?
原因
您可以更改 ItemViewItem
在屏幕上的呈现方式,但不会更改它对用户操作的响应方式。
解决方案
我建议你重新实现 QStyledItemDelegate::editorEvent; in order to adjust the position of the QRect
returned by QStyle::subElementRect when called with QStyle::SE_ItemViewItemCheckIndicator 作为参数。
例子
考虑以下步骤:
- 在你的
TreeItemDelegate
class 中添加一个 public - 将
QStyledItemDelegate::editorEvent
的 default implementation 复制到您的代码中 通过改变
避免调用QStyledItemDelegate
的私有方法const QWidget *widget = QStyledItemDelegatePrivate::widget(option); QStyle *style = widget ? widget->style() : QApplication::style();
到
QStyle *style = option.widget->style();
通过改变
调整checkRect
的位置QRect checkRect = style->subElementRect(QStyle::SE_ItemViewItemCheckIndicator, &viewOpt, widget);
到
QRect checkRect = style->subElementRect(QStyle::SE_ItemViewItemCheckIndicator, &viewOpt, option.widget).adjusted(-10, 0, -10, 0);
editorEvent
方法