如何使项目视图渲染丰富(html)文本在Qt中

假设我的模型有Qt :: DisplayRolestring

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

我想要QTreeView(实际上,任何项目视图)呈现它像一个丰富的文本。 相反,项目视图默认情况下将其呈现为纯文本。 如何实现所需的渲染?


其实这是一个search结果模型。 用户input一个文本,对该文本search一些文档,并向用户显示search结果,其中被search的单词应该比周围的文本更大胆。

我想你可以使用树视图的setItemDelegate方法为你的树视图项目设置自定义画家。 在委托的绘制方法中,您可以使用QTextDocument将项目的文本加载为html并进行渲染。 请检查下面的例子是否适合你:

树视图初始化:

 ... // 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); ... 

自定义委托实现

 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()); } 

希望这有助于问候

update0 :将HTMLDelegate更改为使图标可见,并为所选项目设置不同的笔颜色

 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(); } 

我的答案主要是由@ serge_gubenko的启发。 不过,我们做了一些改进,以便代码在我的应用程序中最终有用。

 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()); } 

这是PyQt转换为我工作的上述答案的组合。 我希望这对于PySide来说也是一样的。

 from PyQt4 import QtCore, QtGui class HTMLDelegate(QtGui.QStyledItemDelegate): def paint(self, painter, option, index): options = QtGui.QStyleOptionViewItemV4(option) self.initStyleOption(options,index) style = QtGui.QApplication.style() if options.widget is None else options.widget.style() doc = QtGui.QTextDocument() doc.setHtml(options.text) options.text = "" style.drawControl(QtGui.QStyle.CE_ItemViewItem, options, painter); ctx = QtGui.QAbstractTextDocumentLayout.PaintContext() # Highlighting text if item is selected #if (optionV4.state & QStyle::State_Selected) #ctx.palette.setColor(QPalette::Text, optionV4.palette.color(QPalette::Active, QPalette::HighlightedText)); textRect = style.subElementRect(QtGui.QStyle.SE_ItemViewItemText, options) painter.save() painter.translate(textRect.topLeft()) painter.setClipRect(textRect.translated(-textRect.topLeft())) doc.documentLayout().draw(painter, ctx) painter.restore() def sizeHint(self, option, index): options = QtGui.QStyleOptionViewItemV4(option) self.initStyleOption(options,index) doc = QtGui.QTextDocument() doc.setHtml(options.text) doc.setTextWidth(options.rect.width()) return QtCore.QSize(doc.idealWidth(), doc.size().height()) 

这个是在PySide。 我没有做大量的自定义绘图,而是将QPainter传递给QLabel并绘制自己。 突出显示从其他答案借来的代码。

 from PySide import QtGui class TaskDelegate(QtGui.QItemDelegate): #http://doc.qt.nokia.com/4.7/qitemdelegate.html#drawDisplay #http://doc.qt.nokia.com/4.7/qwidget.html#render def drawDisplay(self, painter, option, rect, text): label = QtGui.QLabel(text) if option.state & QtGui.QStyle.State_Selected: p = option.palette p.setColor(QtGui.QPalette.WindowText, p.color(QtGui.QPalette.Active, QtGui.QPalette.HighlightedText)) label.setPalette(p) label.render(painter, rect.topLeft(), renderFlags=QtGui.QWidget.DrawChildren)