qtrenderingrichtextqtreeviewqlistview

How to make item view render rich (html) text in Qt


Suppose my model has items with the following string for Qt::DisplayRole

<span>blah-blah <b>some text</b> other blah</span>

I want QTreeView (actually, any item view) to render it like a rich text. Instead, item views render it like a pure text by default. How to achieve the desired rendering?


Actually, this is a search results model. User enters a text, some document is searched against that text and the user is presented with search results, where the words being searched should be bolder than surrounding text.


Solution

  • My answer is mostly inspired by @serge_gubenko's one. However, there were made several improvements so that the code is finally useful in my application.

    class HtmlDelegate : public QStyledItemDelegate
    {
    protected:
        void paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const;
        QSize sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const;
    };
    
    void HtmlDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
        QStyleOptionViewItemV4 optionV4 = option;
        initStyleOption(&optionV4, index);
    
        QStyle *style = optionV4.widget? optionV4.widget->style() : QApplication::style();
    
        QTextDocument doc;
        doc.setHtml(optionV4.text);
    
        /// Painting item without text
        optionV4.text = QString();
        style->drawControl(QStyle::CE_ItemViewItem, &optionV4, painter);
    
        QAbstractTextDocumentLayout::PaintContext ctx;
    
        // Highlighting text if item is selected
        if (optionV4.state & QStyle::State_Selected)
            ctx.palette.setColor(QPalette::Text, optionV4.palette.color(QPalette::Active, QPalette::HighlightedText));
    
        QRect textRect = style->subElementRect(QStyle::SE_ItemViewItemText, &optionV4);
        painter->save();
        painter->translate(textRect.topLeft());
        painter->setClipRect(textRect.translated(-textRect.topLeft()));
        doc.documentLayout()->draw(painter, ctx);
        painter->restore();
    }
    
    QSize HtmlDelegate::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());
    }