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 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.
code of it:
class HTMLDelegate(QStyledItemDelegate):
def __init__(self, parent=None):
super(HTMLDelegate, self).__init__(parent)
def paint(self, painter, option, index):
painter.save()
self.initStyleOption(options, index)
self.doc.setHtml(options.text)
options.text = ""
else options.widget.style()
style.
drawControl(QStyle.
CE_ItemViewItem, options, painter
)
if option.
state & QStyle.
State_Selected: ctx.
palette.
setColor(QPalette.
Text, option.
palette.
color(
textRect
= style.
subElementRect(QStyle.
SE_ItemViewItemText, options
) painter.translate(textRect.topLeft())
self.doc.documentLayout().draw(painter, ctx)
painter.restore()
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()
To copy to clipboard, switch view to plain text mode
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)
self.doc.setDocumentMargin(0)
To copy to clipboard, switch view to plain text mode
Ok, so now to solve that minor visual degradation, I learned 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())
rect = options.rect
options.rect = QRect(rect.x()+3, rect.y(), rect.width(), rect.height())
To copy to clipboard, switch view to plain text mode
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.setDocumentMargin(0)
def paint(self, painter, option, index):
painter.save()
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())
else options.widget.style()
style.
drawControl(QStyle.
CE_ItemViewItem, options, painter
)
if option.
state & QStyle.
State_Selected: ctx.
palette.
setColor(QPalette.
Text, option.
palette.
color(
textRect
= style.
subElementRect(QStyle.
SE_ItemViewItemText, options
) painter.translate(textRect.topLeft())
self.doc.documentLayout().draw(painter, ctx)
painter.restore()
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()
To copy to clipboard, switch view to plain text mode
Bookmarks