You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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;方案一始终返回与初始选项一致的矩形,无法正确获取展开控件的宽度。请问如何正确获取条目内展开控件的宽度?


解决方案

要正确获取树视图中展开/折叠控件的宽度,按以下步骤调整代码:

  1. 修复样式选项的rect属性
    方案一中opt.rect的高度设为0,导致样式无法正确计算子元素尺寸。需给rect设置合理高度,比如使用默认sizeHint的高度,让样式能返回真实的展开控件矩形。

  2. 用样式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();
}
  1. 关键说明
  • 必须确保opt.rect的高度不为0,样式系统需要这个参数来定位子元素。
  • 使用PM_TreeViewIndentation替代硬编码的缩进值,保证在不同样式下的一致性。
  • 展开控件的宽度直接从disclosureRect.width()获取,无需估算。

内容的提问来源于stack exchange,提问作者Igor Mironchik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 04:50:53