具有 html 富文本委托的 PyQt 列表视图将文本位移出位置(包括图片和代码)
PyQt listview with html rich text delegate moves text bit out of place(pic and code included)
得到一个列表视图,其中的项目需要使用粗体文本,因此 html 代表是可行的方法。我环顾四周,找到了几个解决方案,并从中制作了这段代码,但它存在您可以在 gif 中看到的问题,它显示了使用和不使用委托的结果。
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys
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 = QStyleOptionViewItemV4(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()
if __name__ == '__main__':
app = QApplication(sys.argv)
data = ['1','2','3','4','5','6','7','8','9']
main_list = QListView()
main_list.setItemDelegate(HTMLDelegate())
main_list.setModel(QStringListModel(data))
main_list.show()
sys.exit(app.exec_())
我不使用 sizeHint,因为通过我的测试,我感觉它不会影响此行为。
某些属性错误地定位了文本,我已经能够部分地反驳它:
self.doc.setDocumentMargin(0)
默认边距为4,然后将整个item位向右移动
rect = options.rect
options.rect = QRect(rect.x()+3, rect.y(), rect.width(), rect.height())
但我不认为它解决了这个问题的原因,它只是掩盖了它,一旦您尝试添加 icons for example
,它就会再次成为问题
经过更多的挖掘和尝试,调整文本矩形似乎给人一种一切正常的感觉,并且似乎在各种 DE 中表现一致
textRect.adjust(-1, -4, 0, 0)
我不确定这是否是一个错误,但人们会期望 SE_ItemViewItemText
应该自己给出正确的位置
我现在用的就是这个
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
import sys
class HTMLDelegate(QStyledItemDelegate):
def __init__(self, parent=None):
super().__init__()
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()
print(QStyle.State_Selected)
if option.state & QStyle.State_Selected:
ctx.palette.setColor(QPalette.Text, option.palette.color(
QPalette.Active, QPalette.HighlightedText))
else:
ctx.palette.setColor(QPalette.Text, option.palette.color(
QPalette.Active, QPalette.Text))
textRect = style.subElementRect(
QStyle.SE_ItemViewItemText, options)
if index.column() != 0:
textRect.adjust(5, 0, 0, 0)
thefuckyourshitup_constant = 4
margin = (option.rect.height() - options.fontMetrics.height()) // 2
margin = margin - thefuckyourshitup_constant
textRect.setTop(textRect.top() + margin)
painter.translate(textRect.topLeft())
painter.setClipRect(textRect.translated(-textRect.topLeft()))
self.doc.documentLayout().draw(painter, ctx)
painter.restore()
def sizeHint(self, option, index):
return QSize(self.doc.idealWidth(), self.doc.size().height())
if __name__ == '__main__':
app = QApplication(sys.argv)
data = ['1','2','3','4','5','6','7','8','9']
main_list = QListView()
main_list.setItemDelegate(HTMLDelegate())
main_list.setModel(QStringListModel(data))
main_list.show()
sys.exit(app.exec_())
一个老问题,但由于我 运行 遇到过类似的问题,所以我想我会解决您的代码中的一些问题。大多数情况下,它是 self.doc 成员。它不会像你希望的那样工作。 sizeHint() 方法在 paint() 被调用(多次)之前被调用(多次)并且将得到一个空文档(这就是为什么你“不觉得它影响了这种行为”。
你可能会想好,然后在 sizeHint() vs paint() 中初始化文档,但那也是错误的。您的列表只有一个委托和文档,因此文档将始终基于最后一个大小或绘制的文档,因此将 self.doc 作为成员只会为您节省文档构建,考虑到它造成的混乱。
得到一个列表视图,其中的项目需要使用粗体文本,因此 html 代表是可行的方法。我环顾四周,找到了几个解决方案,并从中制作了这段代码,但它存在您可以在 gif 中看到的问题,它显示了使用和不使用委托的结果。
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys
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 = QStyleOptionViewItemV4(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()
if __name__ == '__main__':
app = QApplication(sys.argv)
data = ['1','2','3','4','5','6','7','8','9']
main_list = QListView()
main_list.setItemDelegate(HTMLDelegate())
main_list.setModel(QStringListModel(data))
main_list.show()
sys.exit(app.exec_())
我不使用 sizeHint,因为通过我的测试,我感觉它不会影响此行为。 某些属性错误地定位了文本,我已经能够部分地反驳它:
self.doc.setDocumentMargin(0)
默认边距为4,然后将整个item位向右移动
rect = options.rect
options.rect = QRect(rect.x()+3, rect.y(), rect.width(), rect.height())
但我不认为它解决了这个问题的原因,它只是掩盖了它,一旦您尝试添加 icons for example
,它就会再次成为问题经过更多的挖掘和尝试,调整文本矩形似乎给人一种一切正常的感觉,并且似乎在各种 DE 中表现一致
textRect.adjust(-1, -4, 0, 0)
我不确定这是否是一个错误,但人们会期望 SE_ItemViewItemText
应该自己给出正确的位置
我现在用的就是这个
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
import sys
class HTMLDelegate(QStyledItemDelegate):
def __init__(self, parent=None):
super().__init__()
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()
print(QStyle.State_Selected)
if option.state & QStyle.State_Selected:
ctx.palette.setColor(QPalette.Text, option.palette.color(
QPalette.Active, QPalette.HighlightedText))
else:
ctx.palette.setColor(QPalette.Text, option.palette.color(
QPalette.Active, QPalette.Text))
textRect = style.subElementRect(
QStyle.SE_ItemViewItemText, options)
if index.column() != 0:
textRect.adjust(5, 0, 0, 0)
thefuckyourshitup_constant = 4
margin = (option.rect.height() - options.fontMetrics.height()) // 2
margin = margin - thefuckyourshitup_constant
textRect.setTop(textRect.top() + margin)
painter.translate(textRect.topLeft())
painter.setClipRect(textRect.translated(-textRect.topLeft()))
self.doc.documentLayout().draw(painter, ctx)
painter.restore()
def sizeHint(self, option, index):
return QSize(self.doc.idealWidth(), self.doc.size().height())
if __name__ == '__main__':
app = QApplication(sys.argv)
data = ['1','2','3','4','5','6','7','8','9']
main_list = QListView()
main_list.setItemDelegate(HTMLDelegate())
main_list.setModel(QStringListModel(data))
main_list.show()
sys.exit(app.exec_())
一个老问题,但由于我 运行 遇到过类似的问题,所以我想我会解决您的代码中的一些问题。大多数情况下,它是 self.doc 成员。它不会像你希望的那样工作。 sizeHint() 方法在 paint() 被调用(多次)之前被调用(多次)并且将得到一个空文档(这就是为什么你“不觉得它影响了这种行为”。
你可能会想好,然后在 sizeHint() vs paint() 中初始化文档,但那也是错误的。您的列表只有一个委托和文档,因此文档将始终基于最后一个大小或绘制的文档,因此将 self.doc 作为成员只会为您节省文档构建,考虑到它造成的混乱。