qtreeview更新item行宽和高

7/17/2022 Qt

# qtreeview delegate 中item显示

有时候qtreeview的一个item的文字长度很长时,一般Qt都会缩略他,比如“suncaiyusuncaiyusuncaiyusuncaiyusuncaiyusuncaiyu”会根据策略比如Qt::ElideRight缩成“suncai...”这种。 如果我就是想把它全部显示出来,有两种模式:

# 1.显示在一行上,全部显示

# 1.第一个办法

此时Qt有一个方法,叫

[slot] void QTreeView::resizeColumnToContents(int column) Resizes the column given to the size of its contents. See also columnWidth(), setColumnWidth(), sizeHintForColumn(), and QHeaderView::resizeContentsPrecision(). 他会自动帮你计算。 但是需要注意的是。 resizeColumnToContents有两个相关属性

  1. enum QHeaderView::ResizeMode 列表头的resize模式有一个QHeaderView::ResizeToContents跟随内容一个调整
  2. void QHeaderView::setResizeContentsPrecision(int precision) 调整精度:有点抽象,表示resizeColumnToContents作用的行数。因为treeview有很多行的,precision参数表示作用多少行。比如默认1000 他就会调整1000行,后面的就不管了。特殊值-1表示作用全部行。但是如果有很多数据,这回很耗时间。特殊值0表示值作用当前可见的区域,但这就以为这你要多次刷新,调用resizeColumnToContents。

# 2.第二个办法

自己计算。 其实一行的宽度是根据QTreeview的QHeadView决定的 我们可以在sizeHint中,获取到index对应的font,以及显示的数据,用QFontMertricx计算显示这行数据需要多长的宽度,然后QHeadView::resizeSection()设置header的宽度。(具体没有多测试,可能会有一些小问题,可以看着解决)

# 2. 分行显示,根据header的宽度,自动调整行高度,以便显示全部文字

虽然QTreeView中有一个叫WordWrap的属性,但是设置后发现,没有啥用。而且官方说明里也写了,他并不对全部列管用。(好用只对主列有用) 那就只能自己想办法。还是参考上面第二种办法。首先设置

void setUniformRowHeights(bool uniform)

为false,因为我们不能保证所有行高度一致。 还是在delegate的sizehint中获取header的对应宽度

int wordWidth = fm.width(str); // 显示需要的宽度
int lineCount = wordWidth / headerWidth; // 如果换行,需要多少行
if (wordWidth % heaferWidth > 0) {
  lineCount++;
}
QSize sz;
sz.setHeight(lineCount * fm.height() + (lineCount + 1) * fm.lineSpacing));
return sz;
1
2
3
4
5
6
7
8

同时在delegete中的painter函数中,自己paint一下

if (index.column() == 你需要绘制的那行) {
  painter.drawText(option.rect, Qt::TextWrapAnywhere | Qt::AlignVCenter, index.data(Qt::DisplayRole).value<QString>());
}
1
2
3

如果想要两边留点距离可以option.rect.adjusted(5, 0, 0, -5),当然,在sizeHint计算lineCount的术后需要吧对应的 10像素减去。

但是还有一个最重要的点,当你拖动调整header()的宽度的时候,他是不会变化的,因为没有通知它更新。理论上在delegate中,所有的size变化,都需要发送一个系统的sizeHintChanged(QModelIndex())信号。 或者调用一个偏门的函数 doItemsLayout();