I’m working on a client for a social network. It is written in Qt & Python.
I need to put the timeline into a QListView (think about Twitter or Facebook).
But, QListView can not render rich text, so I use QTextDocument as a delegate.
class HTMLDelegate(QtGui.QStyledItemDelegate):
def paint(self, painter, option, index):
options = QtGui.QStyleOptionViewItemV4(option)
self.initStyleOption(options, index)
options.text = options.text.replace(" ", " ")
style = QtGui.QApplication.style() if options.widget is None else options.widget.style()
doc = QtGui.QTextDocument()
doc.setHtml(options.text)
doc.setTextWidth(option.rect.width())
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()))
It is works, but it doesn’t support all HTML labels.
After a lot of search, I found QWebView, it is a fully-functional HTML viewer. I want to use QWebPage as a delegate for QListView.
So, I tried:
class HTMLDelegate(QtGui.QStyledItemDelegate):
def paint(self, painter, option, index):
options = QtGui.QStyleOptionViewItemV4(option)
self.initStyleOption(options, index)
options.text = options.text.replace(" ", " ")
style = QtGui.QApplication.style() if options.widget is None else options.widget.style()
webPage = QtWebKit.QWebPage(self)
webFrame = webPage.mainFrame()
webPage.setViewportSize(webPage.mainFrame().contentsSize())
webFrame.setHtml(options.text)
#doc.setTextWidth(option.rect.width())
options.text = ""
style.drawControl(QtGui.QStyle.CE_ItemViewItem, options, painter)
#ctx = QtGui.QAbstractTextDocumentLayout.PaintContext()
textRect = style.subElementRect(QtGui.QStyle.SE_ItemViewItemText, options)
painter.save()
painter.translate(textRect.topLeft())
painter.setClipRect(textRect.translated(-textRect.topLeft()))
webFrame.render(painter)
painter.restore()
But it doesn’t work. It just shows blank items.
What wrong did I do?
Or, is there another solution for that situation? I found setItemWidget() can put many widget into a item of QListView, but it will break Model-View.
Ok, so your original problem as I suggested was that you were calling
webPage.setViewportSizebeforewebFrame.setHtml.The
sizeHintis tricky.QWebViewdoesn’t even try, and of course the way web browsers work is that they perform the layout according to the viewport size set by the user. I would suggest that you need to come up with a sensible value the width yourself. You should then be able to get the frame height from thecontentsSize.