如何让包含短横线的文本在QStyledItemDelegate绘制时自动换行
问题原因
Qt的Qt::TextWordWrap标记仅支持在空格、换行符这类默认断字点处换行,日期字符串里的-、:不属于默认断字字符,所以整段日期会被识别为单个超长单词,宽度不足时直接裁切而非换行,和推测的触发原因一致。
解决方案
方案1:插入零宽空格(最简单,无显示副作用)
在日期的分隔符后插入零宽空格\u200B,这个字符不会在界面显示,但会被Qt识别为合法断字点,无需修改其他绘制逻辑:
int flags = Qt::AlignCenter | Qt::TextWordWrap | Qt::TextJustificationForced; switch (index.column()) { case TimeRole: { int boxW = 16, space = 5, leftSpace = 30; QRect textRect = QRect(rect.left() + leftSpace + boxW + space, rect.top(), rect.width() - boxW - space - m_space - leftSpace, rect.height()); QDateTime time = QDateTime::fromMSecsSinceEpoch(model->m_eventTime); QString timeStr = time.toString("yyyy-MM-dd HH:mm:ss"); // 新增:给分隔符后加零宽空格,支持任意位置换行 timeStr.replace("-", "-\u200B").replace(":", ":\u200B"); painter->drawText(textRect, flags, timeStr); break; } }
方案2:手动用QTextLayout计算换行(不修改原字符串)
如果不想修改原始日期字符串,可以手动控制换行逻辑:
// 省略前面textRect计算、timeStr获取的逻辑 QTextLayout textLayout(timeStr, painter->font()); textLayout.setCacheEnabled(true); QTextOption textOption = textLayout.textOption(); textOption.setAlignment(Qt::AlignCenter); textLayout.setTextOption(textOption); int textWidth = textRect.width(); textLayout.beginLayout(); qreal height = 0; while (true) { QTextLine line = textLayout.createLine(); if (!line.isValid()) break; line.setLineWidth(textWidth); height += line.height(); line.setPosition(QPointF(0, height)); } textLayout.endLayout(); // 居中偏移计算 qreal yOffset = (textRect.height() - height) / 2; painter->save(); painter->translate(textRect.left(), textRect.top() + yOffset); textLayout.draw(painter, QPointF(0, 0)); painter->restore();
额外注意事项
如果换行后文本高度超过原单元格行高,还需要重写QStyledItemDelegate的sizeHint方法,根据文本内容计算实际需要的单元格高度,避免上下内容被裁切。
错误效果展示

内容的提问来源于stack exchange,提问作者Tiina
相关产品推荐
相关产品推荐

