I have a custom delegate derived from QStyleOptionViewItem which is trying to draw multiline (wordwrap) a long line of text in the paint method. After doing some search and Qt doc reading, I looks like I need to use QTextLayout for such task, below is the code I have which still puts the text in one single line, any hints on how to wrapping the line around length of the QStyleOptionViewItem passed in? Thanks!!
void Delegate::paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
painter->save();
painter->translate(option.rect.topLeft());
QString title = index.data(Qt::DisplayRole).toString();
QTextLayout * layout = new QTextLayout(title, QApplication::font());
layout->beginLayout();
QTextLine line = layout->createLine();
while (line.isValid()) {
line.setLineWidth(option.rect.width());
line = layout->createLine();
}
layout->endLayout();
layout->draw(painter, QPointF(0, 0));
painter->restore();
}
Since I can’t self answer, I will just post my findings here.
I found couple issues with my code:
- The test string I are one word consisted of 200 characters and by default QTextLayout does word wrap. So I have to explicitly call QTextLayout::setWrapMode() for that test case to wrap.
- I am not setting position for each line.
This is my paint method in Ruby:
def paint painter, styleOptionViewItem, modelIndex
painter.save
painter.translate styleOptionViewItem.rect.top_left
marked_text = modelIndex.data(Qt::DisplayRole).value
font = Qt::Application::font()
text_layout = Qt::TextLayout.new marked_text
text_layout.setFont font
text_option = Qt::TextOption.new
text_option.setWrapMode(Qt::TextOption::WrapAtWordBoundaryOrAnywhere)
text_layout.setTextOption text_option
text_layout.beginLayout
fm = Qt::FontMetrics.new font
font_height = fm.height
i = 0
while i< LINE_LIMIT do
line = text_layout.createLine
break if (!line.isValid())
line.setLineWidth(styleOptionViewItem.rect.width)
line.setPosition(Qt::PointF.new(0, font_height * i))
i += 1
end
text_layout.endLayout
text_layout.draw painter, Qt::PointF.new(0, 0)
painter.restore
end
I had to do same task for a while.
While I used simple
QPainter::drwText, I bumped into this issue.To make word wrap work, you should:
uniformRowHeightproperty of view.handle
sizeHintcorrectly. By default this function return0, you should override it to returnQt::SizeHintrole of item data.But you should also set correct value for
Qt::SizeHintrole. You can useQFontMetrics::boundingRectto calculatesizeHint, but you should ensure you use same font when calculatingsizeHintand when drawing item. OnWindows 7I had an issue, that font ofQStandardItemdidn’t coincide withQListView‘s one.Note, that it is bad idea to calculate
sizeHintfrom scratch every time it requested, because it works really slow.