Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

[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 ...

    1. keep doc outside sizeHint.
    2. call doc.setHtml(optionV4.text); only when content has changed.
    3. call #2 outside sizeHint
    4. call doc.setTextWidth(optionV4.rect.width()); also only when content has changed
    5. call #4 outside sizeHint
    6. 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 qualifiers

    But 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!


Log in to reply