如何使用QStyledItemDelegate绘制()

问题描述 投票:0回答:1

我正在使用PySide2,但在QStyledItemDelegate子类中找不到有关如何使用paint()函数的任何文档。我不是新手,但是到目前为止是可以理解的,但是在使用PySide2时遇到了麻烦。

我想用自己的ListWidgetItem替换我的QtWidgets.QListWidgetItem并正确显示它们,如下所示:enter image description here

因此,在ListWidgetItem的左侧,图标在ListWidgetItem的名称的右侧,并在描述的下方。

这里是代码:

from PySide2 import QtWidgets, QtCore, QtGui
from PySide2.QtGui import *
import sys

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__()

        self.setWindowTitle('Test Window')
        self.setStyleSheet("background-color: rgb(65, 65, 65);")

        mainWidget = QtWidgets.QWidget(self)
        self.setCentralWidget(mainWidget)
        self.boxLayout = QtWidgets.QVBoxLayout()
        mainWidget.setLayout(self.boxLayout)

        # Add Widgets
        self.textField = QtWidgets.QLineEdit()
        self.listView = QtWidgets.QListWidget()

        self.textField.textChanged.connect(self.onTextChanged)

        self.boxLayout.addWidget(self.textField)
        self.boxLayout.addWidget(self.listView)

        self.textField.setFocus()


    def onTextChanged(self, ):
        titles = ['Monkey', 'Giraffe', 'Dragon', 'Bull']
        descriptions = ['Almost a homo sapiens sapiens', 'I am a Giraffe!', 'Can fly and is hot on spices', 'Horny...']

        if self.textField.text() == '' or self.textField.text().isspace() or self.textField.text() == ' ':
            if self.listView.count() > 0:
                self.listView.clear()
        else:
            if self.listView.count() > 0:
                self.listView.clear()
            for x in range(len(titles)):
                if self.textField.text() in titles[x]:
                    item = ListWidgetItem(titles[x])
                    self.listView.addItem(item)
                    self.listView.setCurrentRow(0)
                    continue


class ListWidgetItem(QtWidgets.QListWidgetItem):
    def __init__(self, title = '', description = '', icon = QtGui.QIcon()):
        super(ListWidgetItem, self).__init__()
        self.title = title
        self.description = description
        self.icon = icon


class ListViewStyle(QtWidgets.QStyledItemDelegate):
    def __init__(self, parent, itemModel):
        super(ListViewStyle, self).__init__(parent)
        self.itemModel = itemModel

    def sizeHint(self, option, index):
        if index:
            return QtCore.QSize(40, 40)

    def paint(self, painter, option, index):
        super(ListViewStyle, self).paint(painter, option, index)

if __name__ == '__main__':
    app = QtWidgets.QApplication.instance()
    if app is None: 
        app = QtWidgets.QApplication(sys.argv)

    w = MainWindow()
    w.show()
    #sys.exit(app.exec_())

信息:在onTextChanged()中,ListWidgetItem将添加到QListWidget,但绘制不正确,基本上为空。

QListWidgetItem与QListView有什么显着区别吗?

python pyside2 qlistwidget qlistwidgetitem
1个回答
0
投票

代表只绘制并且不关心哪个元素提供了信息,因为该类使用QModelIndex和相同的模型来获取信息,因此在my previous solution中,我使用了QStandardItemModel,后者使用了QStandardItem,在当前情况下,使用了QListWidget与QListWidgetItem无关。我的代表只希望标题,描述和图标的信息分别与TitleRole,DescriptionRole和IconRole相关。

另一方面,删除项目并不好,但是在必要时最好隐藏它们或使其可见。

考虑到上述,使用QListWidget的解决方案如下:

import sys

from PySide2 import QtWidgets, QtCore, QtGui

TitleRole = QtCore.Qt.UserRole + 1000
DescriptionRole = QtCore.Qt.UserRole + 1001
IconRole = QtCore.Qt.UserRole + 1002


class ListWidgetItem(QtWidgets.QListWidgetItem):
    def __init__(self, title="", description="", icon=QtGui.QIcon()):
        super(ListWidgetItem, self).__init__()
        self.title = title
        self.description = description
        self.icon = icon

    @property
    def title(self):
        return self.data(TitleRole)

    @title.setter
    def title(self, title):
        self.setData(TitleRole, title)

    @property
    def description(self):
        return self.data(DescriptionRole)

    @description.setter
    def description(self, description):
        self.setData(DescriptionRole, description)

    @property
    def icon(self):
        return self.data(IconRole)

    @icon.setter
    def icon(self, icon):
        self.setData(IconRole, icon)


class StyledItemDelegate(QtWidgets.QStyledItemDelegate):
    def sizeHint(self, option, index):
        return QtCore.QSize(50, 50)

    def paint(self, painter, option, index):
        super(StyledItemDelegate, self).paint(painter, option, index)
        title = index.data(TitleRole)
        description = index.data(DescriptionRole)
        icon = index.data(IconRole)

        mode = QtGui.QIcon.Normal
        if not (option.state & QtWidgets.QStyle.State_Enabled):
            mode = QtGui.QIcon.Disabled
        elif option.state & QtWidgets.QStyle.State_Selected:
            mode = QtGui.QIcon.Selected

        state = (
            QtGui.QIcon.On
            if option.state & QtWidgets.QStyle.State_Open
            else QtGui.QIcon.Off
        )
        iconRect = QtCore.QRect(option.rect)
        iconRect.setSize(QtCore.QSize(40, 40))
        icon.paint(
            painter, iconRect, QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter, mode, state
        )

        titleFont = QtGui.QFont(option.font)
        titleFont.setPixelSize(20)
        fm = QtGui.QFontMetrics(titleFont)
        titleRect = QtCore.QRect(option.rect)
        titleRect.setLeft(iconRect.right())
        titleRect.setHeight(fm.height())

        color = (
            option.palette.color(QtGui.QPalette.BrightText)
            if option.state & QtWidgets.QStyle.State_Selected
            else option.palette.color(QtGui.QPalette.WindowText)
        )
        painter.save()
        painter.setFont(titleFont)
        pen = painter.pen()
        pen.setColor(color)
        painter.setPen(pen)
        painter.drawText(titleRect, title)
        painter.restore()

        descriptionFont = QtGui.QFont(option.font)
        descriptionFont.setPixelSize(15)
        fm = QtGui.QFontMetrics(descriptionFont)
        descriptionRect = QtCore.QRect(option.rect)
        descriptionRect.setTopLeft(titleRect.bottomLeft())
        descriptionRect.setHeight(fm.height())
        painter.save()
        painter.setFont(descriptionFont)
        pen = painter.pen()
        pen.setColor(color)
        painter.setPen(pen)
        painter.drawText(
            descriptionRect,
            fm.elidedText(description, QtCore.Qt.ElideRight, descriptionRect.width()),
        )
        painter.restore()


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__()

        self.setWindowTitle("Test Window")
        self.setStyleSheet("background-color: rgb(65, 65, 65);")

        mainWidget = QtWidgets.QWidget(self)
        self.setCentralWidget(mainWidget)
        self.boxLayout = QtWidgets.QVBoxLayout()
        mainWidget.setLayout(self.boxLayout)

        # Add Widgets
        self.textField = QtWidgets.QLineEdit()
        self.listView = QtWidgets.QListWidget()

        self.textField.textChanged.connect(self.onTextChanged)

        self.boxLayout.addWidget(self.textField)
        self.boxLayout.addWidget(self.listView)
        self.fill_model()

        self.textField.setFocus()

        self.listView.setItemDelegate(StyledItemDelegate(self))

    def fill_model(self):
        titles = ["Monkey", "Giraffe", "Dragon", "Bull"]
        descriptions = [
            "Almost a homo sapiens sapiens",
            "I am a Giraffe!",
            "Can fly and is hot on spices",
            "Horny...",
        ]

        for title, description in zip(titles, descriptions):
            it = ListWidgetItem(title=title, description=description)
            self.listView.addItem(it)

    @QtCore.Slot(str)
    def onTextChanged(self, text):
        text = text.strip()
        if text:
            for i in range(self.listView.count()):
                it = self.listView.item(i)
                if it is not None:
                    it.setHidden(text.lower() not in it.title.lower())
        else:
            for i in range(self.listView.count()):
                it = self.listView.item(i)
                if it is not None:
                    it.setHidden(False)


if __name__ == "__main__":
    app = QtWidgets.QApplication.instance()
    if app is None:
        app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.