PDA

View Full Version : HTML delegate for QListView to look exactly as default, I am close, pls check [gifs]



DoTheEvo
23rd April 2015, 17:27
PyQt, but probably should not play that big of a role.

So, what I want is to have listview that looks and acts exactly like the default listview, but that does support html tags in the text.

There are several stackoverflow (http://stackoverflow.com/questions/1956542/how-to-make-item-view-render-rich-html-text-in-qt) questions and from all the answers I rustled up something that comes pretty close, but would like someone who actually understands delegates to look at it, if I am not doing something wrong, choosing wrong approach.

Here is the most basic one that got me pretty close to what I want.
Pls make note that theres no use of custom sizeHint(), only paint(), also theres no ues setClipRect() since it caused issues on KDE and when removed everything seems fine.

http://i.imgur.com/xD0LTqp.gif

code of it:



class HTMLDelegate(QStyledItemDelegate):
def __init__(self, parent=None):
super(HTMLDelegate, self).__init__(parent)
self.doc = QTextDocument(self)

def paint(self, painter, option, index):
painter.save()

options = QStyleOptionViewItem(option)
self.initStyleOption(options, index)

self.doc.setHtml(options.text)
options.text = ""

style = QApplication.style() if options.widget is None \
else options.widget.style()
style.drawControl(QStyle.CE_ItemViewItem, options, painter)

ctx = QAbstractTextDocumentLayout.PaintContext()

if option.state & QStyle.State_Selected:
ctx.palette.setColor(QPalette.Text, option.palette.color(
QPalette.Active, QPalette.HighlightedText))

textRect = style.subElementRect(QStyle.SE_ItemViewItemText, options)
painter.translate(textRect.topLeft())
self.doc.documentLayout().draw(painter, ctx)

painter.restore()


Now, the problem is that a selection highlighted seems to be somehow cut, not done right.
The way I find to fix it was to set document margin to 0 or 1 (default is 4), but that now moves the items all the way to the left, touching the left line.


self.doc.setDocumentMargin(0)

http://i.imgur.com/iPnGsWa.gif

Ok, so now to solve that minor visual degradation, I learned (http://qt-articles.blogspot.com/2010/07/how-to-customize-listview-in-qt-using.html) that I can set the items starting points and after adding this code in to paint() the listview looks the same as default



rect = options.rect
options.rect = QRect(rect.x()+3, rect.y(), rect.width(), rect.height())


http://i.imgur.com/VMDMo0s.gif

And so this is the final code, but I feel like it could have go with margin 4 and not moving the items by few pixels right, only if I knew how to fix that highlight selection...
Also I am kinda worried that theres something needed that might cause it act wonky even if its alright on my system...



class HTMLDelegate(QStyledItemDelegate):
def __init__(self, parent=None):
super(HTMLDelegate, self).__init__(parent)
self.doc = QTextDocument(self)
self.doc.setDocumentMargin(0)

def paint(self, painter, option, index):
painter.save()

options = QStyleOptionViewItem(option)
self.initStyleOption(options, index)

self.doc.setHtml(options.text)
options.text = ""

rect = options.rect
options.rect = QRect(rect.x()+3, rect.y(), rect.width(), rect.height())

style = QApplication.style() if options.widget is None \
else options.widget.style()
style.drawControl(QStyle.CE_ItemViewItem, options, painter)

ctx = QAbstractTextDocumentLayout.PaintContext()

if option.state & QStyle.State_Selected:
ctx.palette.setColor(QPalette.Text, option.palette.color(
QPalette.Active, QPalette.HighlightedText))

textRect = style.subElementRect(QStyle.SE_ItemViewItemText, options)
painter.translate(textRect.topLeft())
self.doc.documentLayout().draw(painter, ctx)

painter.restore()