如何在QStyledItemDelegate的sizeHint()方法中获取展开控件的QRect
问题描述
我正在实现一个自定义QStyledItemDelegate,需要在sizeHint()方法中获取展开/折叠控件的QRect,从而为条目计算正确的大小提示。我尝试了两种方案:
方案一代码
QSize WordWrapItemDelegate::sizeHint( const QStyleOptionViewItem & option, const QModelIndex & index ) const { QStyleOptionViewItem opt = option; initStyleOption( &opt, index ); opt.rect = { 0, 0, m_parent->header()->sectionSize( index.column() ), 0 }; QStyle * style = opt.widget ? opt.widget->style() : QApplication::style(); auto iconRect = style->subElementRect( QStyle::SE_TreeViewDisclosureItem, &opt, opt.widget ); qDebug() << iconRect; return option.fontMetrics.boundingRect( QRect( 0, 0, m_parent->header()->sectionSize( index.column() ) - option.decorationSize.width() /** level * 2*/, 0 ), Qt::AlignLeft | Qt::TextWordWrap, index.data( Qt::DisplayRole ).toString() ).size(); }
方案二代码
QSize WordWrapItemDelegate::sizeHint( const QStyleOptionViewItem & option, const QModelIndex & index ) const { int level = 1; auto i = index; while( i.parent().isValid() ) { ++level; i = i.parent(); } return option.fontMetrics.boundingRect( QRect( 0, 0, m_parent->header()->sectionSize( index.column() ) - option.decorationSize.width() * level * 2, 0 ), Qt::AlignLeft | Qt::TextWordWrap, index.data( Qt::DisplayRole ).toString() ).size(); }
方案二可以运行,但使用了硬编码的option.decorationSize.width() * level * 2;方案一始终返回与初始选项一致的矩形,无法正确获取展开控件的宽度。请问如何正确获取条目内展开控件的宽度?
解决方案
要正确获取树视图中展开/折叠控件的宽度,按以下步骤调整代码:
修复样式选项的
rect属性
方案一中opt.rect的高度设为0,导致样式无法正确计算子元素尺寸。需给rect设置合理高度,比如使用默认sizeHint的高度,让样式能返回真实的展开控件矩形。用样式API获取标准缩进量
不要硬编码缩进倍数,通过QStyle::PM_TreeViewIndentation获取系统或自定义样式定义的层级缩进值,适配性更强。
修改后的完整代码:
QSize WordWrapItemDelegate::sizeHint( const QStyleOptionViewItem & option, const QModelIndex & index ) const { QStyleOptionViewItem opt = option; initStyleOption( &opt, index ); // 获取默认sizeHint的高度,作为临时rect的高度 QSize defaultSize = QStyledItemDelegate::sizeHint(option, index); // 设置完整的rect参数:宽度为列宽,高度为默认高度 opt.rect = QRect(0, 0, m_parent->header()->sectionSize(index.column()), defaultSize.height()); QStyle * style = opt.widget ? opt.widget->style() : QApplication::style(); // 获取展开/折叠控件的矩形 QRect disclosureRect = style->subElementRect(QStyle::SE_TreeViewDisclosureItem, &opt, opt.widget); // 计算当前条目的层级 int level = 0; auto currentIndex = index; while(currentIndex.parent().isValid()){ level++; currentIndex = currentIndex.parent(); } // 获取样式定义的层级缩进量 int indentPerLevel = style->pixelMetric(QStyle::PM_TreeViewIndentation, &opt, opt.widget); // 计算文本可用宽度:列宽 - 展开控件宽度 - 总缩进量 int availableWidth = opt.rect.width() - disclosureRect.width() - (indentPerLevel * level); // 计算带自动换行的文本尺寸 return option.fontMetrics.boundingRect( QRect(0, 0, availableWidth, 0), Qt::AlignLeft | Qt::TextWordWrap, index.data(Qt::DisplayRole).toString() ).size(); }
- 关键说明
- 必须确保
opt.rect的高度不为0,样式系统需要这个参数来定位子元素。 - 使用
PM_TreeViewIndentation替代硬编码的缩进值,保证在不同样式下的一致性。 - 展开控件的宽度直接从
disclosureRect.width()获取,无需估算。
内容的提问来源于stack exchange,提问作者Igor Mironchik
相关产品推荐
相关产品推荐

