[SOLVED] QTableView - custom sizeHint() implementation slow
-
Hi guys,
I'm using a QTableView to display a bunch of information. Since I need rich text support in the cells I implemented a custom item delegate with QTextDocument and overwrote the sizeHint();
However, the sizeHint() function causes some problems: It slows everything down really badly. By that I mean, that e.g. moving the cursor over a few cells, the highlighting really lags behind.Here's the code that I use for the Delegate and the sizeHint:
@void RichTextDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const {QStyleOptionViewItemV4 options = option;
initStyleOption(&options, index);painter->save();
QTextDocument doc;
doc.setTextWidth(options.rect.width());
doc.setHtml(options.text);options.text = "";
options.widget->style()->drawControl(QStyle::CE_ItemViewItem, &options, painter);painter->translate(options.rect.left(), options.rect.top());
QRect clip(0, 0, options.rect.width(), options.rect.height());QPen greyPen(Qt::lightGray);
painter->setPen(greyPen);
painter->drawLine(0,options.rect.height(),options.rect.width(),options.rect.height());
painter->drawLine(0,0,options.rect.width(),0);painter->setClipRect(clip);
QAbstractTextDocumentLayout::PaintContext ctx;ctx.clip = clip;
doc.documentLayout()->draw(painter, ctx);painter->restore();
}
QSize RichTextDelegate::sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const {
QStyleOptionViewItemV4 optionV4 = option;
initStyleOption(&optionV4, index);
QTextDocument doc;
doc.setHtml(optionV4.text);
doc.setTextWidth(optionV4.rect.width());
return QSize(doc.idealWidth(), doc.size().height());}@
I know, the laggish behaviour is caused by sizeHint, because if I remove its implementation everything works just fine... Any idea, what I can do to improve the code, stopping it to be "laggish"?
Appreciate any help!
Ps: I tested it both under Qt 4.8.5 and Qt 5.1.1, same result.
-
You are recreating QTextDocument doc everytime sizeHint is called. It may be called a million times on just one refresh of a screen.
I would recommend to ...
- keep doc outside sizeHint.
- call doc.setHtml(optionV4.text); only when content has changed.
- call #2 outside sizeHint
- call doc.setTextWidth(optionV4.rect.width()); also only when content has changed
- call #4 outside sizeHint
- you can keep the last line maybe with a little modification :)
return QSize(m_doc.idealWidth(), m_doc.size().height());
-
That makes sense, thanks! No wonder it's slow.
However, I can't figure out how to check if the content has changed. The problem is, that both functions are const, i.e. assigning anything from there to e.g. a global variable doesn't work:
(header)
QString txt;(paint/sizehint)
txt = options.text-> doesn't compile:
passing 'const QString' as 'this' argument of 'QString& QString::operator=(const QString&)' discards qualifiersBut how else could I keep track of changes of the content?
-
Okay, I think I got it now, the (now deleted?) comment about the mutable keyword helped a lot.
No I check for changes in content and/or changes in the optionV4.rect, and only if at least one of them changed then I recalculate the sizeHint. Here's the code I came up with:(header)
@private:
mutable QHash<QPair<int,int>, QString> txt;
mutable QHash<QPair<int,int>, QSize> docSize;
mutable QHash<QPair<int,int>, QRect> optionRect;@(source)
@QSize RichTextDelegate::sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const {QStyleOptionViewItemV4 optionV4 = option;
initStyleOption(&optionV4, index);QPair<int,int> p;
p.first = index.row();
p.second = index.column();if(txt[p] != optionV4.text || optionRect[p] != optionV4.rect) {
QTextDocument doc;
doc.setHtml(optionV4.text);
doc.setTextWidth(optionV4.rect.width());txt[p] = optionV4.text;
docSize[p] = QSize(doc.idealWidth(),doc.size().height());
optionRect[p] = optionV4.rect;}
return docSize[p];
}@
I hope I haven't missed something important, but, as far as I can tell, that works quite well.
Thanks a million to Agroni and the other person of the deleted comment!