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