【问题标题】:Initial paint of QStyledItemDelegate has the wrong heightQStyledItemDelegate 的初始绘制高度错误
【发布时间】:2020-12-06 19:58:14
【问题描述】:

我正在尝试使用QStyledItemDelegate 和我的QListView 在项目中显示富文本。

第一次绘制项目时,它的高度太小。如果然后我将鼠标悬停在该项目上,它将以正确的高度重新绘制。以下是初始绘制和重绘的屏幕截图。

如何使初始绘制的高度正确?

演示问题的示例代码:

from PySide2 import QtCore, QtGui, QtWidgets


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

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

        self.initStyleOption(option, index)
        self.doc.setHtml(option.text)

        option_no_text = QtWidgets.QStyleOptionViewItem(option)
        option_no_text.text = ''
        style = QtWidgets.QApplication.style() if option_no_text.widget is None else option_no_text.widget.style()
        style.drawControl(QtWidgets.QStyle.CE_ItemViewItem, option_no_text, painter)

        margin_top = (option.rect.height() - self.doc.size().height()) // 2
        text_rect = style.subElementRect(QtWidgets.QStyle.SE_ItemViewItemText, option_no_text, None)
        text_rect.setTop(text_rect.top() + margin_top)

        painter.translate(text_rect.topLeft())
        painter.setClipRect(text_rect.translated(-text_rect.topLeft()))

        context = QtGui.QAbstractTextDocumentLayout.PaintContext()
        self.doc.documentLayout().draw(painter, context)

        painter.restore()

    def sizeHint(self, option, index):
        other = super().sizeHint(option, index)
        w = min(self.doc.idealWidth(), other.width())
        h = max(self.doc.size().height(), other.height())
        return QtCore.QSize(w, h)


class ExampleWidget(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()

        item = QtGui.QStandardItem()
        item.setText('Example<br><span style="font-size: 14pt; font-weight: bold;">Example<br>Example<br>Example</span>', )

        model = QtGui.QStandardItemModel()
        model.appendRow(item)

        self.listview = QtWidgets.QListView(parent=self)
        self.listview.setModel(model)

        delegate = RichTextItemDelegate(self.listview)
        self.listview.setItemDelegate(delegate)


app = QtWidgets.QApplication([])
example = ExampleWidget()
example.resize(320, 240)
example.show()
app.exec_()

【问题讨论】:

  • 我没有重现你的问题,你可以指出你的环境特征:python版本,pyside2版本,操作系统等
  • Windows 10、Python 3.7.6、PySide2 5.15.0。
  • 我看到sizeHint()paint() 被调用之前被调用了5 次......我只是不知道该怎么做。
  • mmm,好像是个bug,加print(w, h)会得到什么?在设置模型之前尝试设置委托
  • 移动setItemDelegate 无效。我看到一个调用序列,如:sizeHint: 8.0, 24.0; paint; sizeHint: 107.0, 108.0;。因为self.doc.setHtml 直到paint 才会被调用,我认为这就是我所期望的。我想知道如何在调用paint 之前设置文档文本。

标签: python pyside2 qstyleditemdelegate


【解决方案1】:

所以我认为初始绘制的大小是错误的,因为 sizeHint() 函数在知道项目文本是什么之前无法返回好的值。在我的原始代码中,直到调用 paint() 才设置文本。

我为sizeHint() 使用了以下内容,它似乎有效:

def sizeHint(self, option: QtWidgets.QStyleOptionViewItem, index: QtCore.QModelIndex) -> QtCore.QSize:
    self.doc.setHtml(index.data())
    doc_size = self.doc.size()
    doc_width = int(math.ceil(doc_size.width()))
    doc_height = int(math.ceil(doc_size.height()))

    item_size = super().sizeHint(option, index)

    w = min(doc_width, item_size.width())
    h = max(doc_height, item_size.height())

    return QtCore.QSize(w, h)

请注意...我不知道在sizeHint() 内部调用self.doc.setHtml() 的含义是什么。另外,由于某种原因,super().sizeHint() 为我返回了一个非常大的宽度值,我不知道为什么,这就是为什么我调用 min() 而不是 max()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多