QStyledItemDelegate的初始绘制具有错误的高度

问题描述

我正在尝试将QStyledItemDelegateQListView一起使用,以在项目中显示富文本。

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

如何使初始油漆达到合适的高度?

Initial height is too small.

After first repaint the height is just right.

演示此问题的示例代码:

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

解决方法

因此,我相信初始绘制的尺寸是错误的,因为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)

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

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...