Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 945
Anthony Serdyukov Avatar asked Dec 24 '09 03:12

Anthony Serdyukov


2 Answers

I guess you can use setItemDelegate method of the treeview to setup custom painter for your treeview items. In the delegate's paint method you can use QTextDocument to load item's text as html and render it. Please check if an example below would work for you:

treeview initialization:

...     // create simple model for a tree view     QStandardItemModel *model = new QStandardItemModel();     QModelIndex parentItem;     for (int i = 0; i < 4; ++i)     {         parentItem = model->index(0, 0, parentItem);         model->insertRows(0, 1, parentItem);         model->insertColumns(0, 1, parentItem);         QModelIndex index = model->index(0, 0, parentItem);         model->setData(index, "<span>blah-blah <b>some text</b> other blah</span>");     }     // create custom delegate     HTMLDelegate* delegate = new HTMLDelegate();     // set model and delegate to the treeview object     ui->treeView->setModel(model);     ui->treeView->setItemDelegate(delegate); ... 

custom delegate implementation

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 options = option;     initStyleOption(&options, index);      painter->save();      QTextDocument doc;     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());     doc.drawContents(painter, clip);      painter->restore(); }  QSize HTMLDelegate::sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const {     QStyleOptionViewItemV4 options = option;     initStyleOption(&options, index);      QTextDocument doc;     doc.setHtml(options.text);     doc.setTextWidth(options.rect.width());     return QSize(doc.idealWidth(), doc.size().height()); } 

hope this helps, regards

update0: changes to HTMLDelegate to make icons visible and different pen color for selected items

void HTMLDelegate::paint(QPainter* painter, const QStyleOptionViewItem & option, const QModelIndex &index) const {     QStyleOptionViewItemV4 options = option;     initStyleOption(&options, index);      painter->save();      QTextDocument doc;     doc.setHtml(options.text);      options.text = "";     options.widget->style()->drawControl(QStyle::CE_ItemViewItem, &options, painter);      // shift text right to make icon visible     QSize iconSize = options.icon.actualSize(options.rect.size());     painter->translate(options.rect.left()+iconSize.width(), options.rect.top());     QRect clip(0, 0, options.rect.width()+iconSize.width(), options.rect.height());      //doc.drawContents(painter, clip);      painter->setClipRect(clip);     QAbstractTextDocumentLayout::PaintContext ctx;     // set text color to red for selected item     if (option.state & QStyle::State_Selected)         ctx.palette.setColor(QPalette::Text, QColor("red"));     ctx.clip = clip;     doc.documentLayout()->draw(painter, ctx);      painter->restore(); } 
like image 108
serge_gubenko Avatar answered Oct 01 '22 04:10

serge_gubenko


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()); } 
like image 33
Anthony Serdyukov Avatar answered Oct 01 '22 03:10

Anthony Serdyukov