使用 QStyledItemDelegates 作为 QListView 中的自定义项

Posted

技术标签:

【中文标题】使用 QStyledItemDelegates 作为 QListView 中的自定义项【英文标题】:Using QStyledItemDelegates as custom items in QListView 【发布时间】:2019-10-23 19:57:58 【问题描述】:

我想设计一个自定义的ListView 小部件,它具有与此类似的自定义项: https://i.stack.imgur.com/iTNbN.png

但是,qt 文档和一些 *** 帖子指出,理想情况下应该使用QStyleItemDelegate。我以前从未与“代表”合作过,但据我的研究了解,ListView 调用它们来绘制/渲染每个项目。

我在另一个项目 (https://github.com/pyblish/pyblish-lite/blob/master/pyblish_lite/delegate.py) 中找到了一个委托示例,他们手工绘制所有内容/实际上是通过绘制矩形来重建整个小部件。

这对我来说似乎有点不切实际,因为大多数时候自定义项目小部件可以是现有小部件的组合。看看上面的截图。它本质上包含一个 Qlabel、QPixmap 和四个 DoubleSpinBox。

问题:您将如何使用其中已经存在的绘画/渲染方法,而不是自己手动绘制所有内容? 这样您就可以从现有的成员方法中获益,并且可以使用布局来构建您的小部件。

例如,第一个 ListViewItem 应该将模型数据传递给委托,以便可以将self.lightGroupName QLabel 的文本设置为“Light1”。

非常感谢任何帮助,因为我不知道如何从这里继续:

from PySide2 import QtCore, QtGui, QtWidgets

class LightDelagate(QtWidgets.QStyledItemDelegate): #custom item view
    def __init__(self, parent=None):
        super(LightDelagate, self).__init__(parent)
        self.setupUI()

    def setupUI(self):
        self.masterWidget = QtWidgets.QWidget()

        #Light Group Header 
        self.hlayLightHeader = QtWidgets.QHBoxLayout()
        self.lightGroupName = QtWidgets.QLabel("Checker")
        self.hlayLightHeader.addWidget(self.lightGroupName)

        #Light AOV Preview
        self.lightPreview = QtWidgets.QLabel()
        #set size 
        self.aovThumbnail = QtGui.QPixmap(180, 101)
        #self.lightPreview.setPixmap(self.aovThumbnail.scaled(self.lightPreview.width(), self.lightPreview.height(), QtCore.Qt.KeepAspectRatio))

        # #Color Dials
        # self.hlayColorDials = QtWidgets.QHBoxLayout()
        # self.rgbDials = QtWidgets.QHBoxLayout()
        # self.rDial = QtWidgets.QDoubleSpinBox()
        # self.rDial.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons)
        # self.gDial = QtWidgets.QDoubleSpinBox()
        # self.gDial.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons)
        # self.bDial = QtWidgets.QDoubleSpinBox()
        # self.bDial.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons)
        # self.rgbDials.addWidget(self.rDial)
        # self.rgbDials.addWidget(self.gDial)
        # self.rgbDials.addWidget(self.bDial)
        # #Exposure
        # self.hlayExposureDials = QtWidgets.QHBoxLayout()
        # self.exposureDial = QtWidgets.QDoubleSpinBox()
        # self.exposureDial.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons)

        # self.hlayExposureDials.addWidget(self.exposureDial)
        # self.hlayColorDials.addLayout(self.rgbDials)
        # self.hlayColorDials.addLayout(self.hlayExposureDials)

        #entire layout
        self.vlayWidget = QtWidgets.QVBoxLayout()
        self.vlayWidget.addLayout(self.hlayLightHeader)
        self.vlayWidget.addWidget(self.lightPreview)
        # self.vlayWidget.addLayout(self.hlayColorDials)
        self.vlayWidget.setContentsMargins(2,2,2,2)
        self.vlayWidget.setSpacing(2)
        self.masterWidget.setLayout(self.vlayWidget)



    def paint(self, painter, option, index):
        rowData = index.model().data(index, QtCore.Qt.DisplayRole)
        self.lightGroupName.setText(rowData[0])
        print (option.rect)
        painter.drawRect(option.rect)
        painter.drawText()
    def sizeHint(self, option, index):
        return QtCore.QSize(200, 150)

class LightListModel(QtCore.QAbstractListModel): #data container for list view
    def __init__(self, lightList= None):
        super(LightListModel, self).__init__()
        self.lightList = lightList or []

    #reimplement
    def rowCount(self, index):
        return len(self.lightList)

    def data(self, index, role):
        if role == QtCore.Qt.DisplayRole:
            lightGroupData = self.lightList[index.row()]
            return lightGroupData


class LightListView(QtWidgets.QListView): #
    def __init__(self):
        super(LightListView, self).__init__()
        self.setFlow(QtWidgets.QListView.LeftToRight)
        self.setItemDelegate(LightDelagate(self))
        self.setMinimumWidth(1880)

lightListTest = [ 
    ('Light1' , 'lightList' : [], 'lightColor': (0,0,0), 'mod_exposure': 1, 'mod_color' : (0,0,0)),
    ('Light2' , 'lightList' : [], 'lightColor': (0,0,0), 'mod_exposure': 1, 'mod_color' : (0,0,0)),
    ('Light3' , 'lightList' : [], 'lightColor': (0,0,0), 'mod_exposure': 1, 'mod_color' : (0,0,0)),
    ('Light4' , 'lightList' : [], 'lightColor': (0,0,0), 'mod_exposure': 1, 'mod_color' : (0,0,0))
]

app = QtWidgets.QApplication([])
LLV = LightListView()
model = LightListModel(lightList=lightListTest)
LLV.setModel(model)
LLV.show()
LLV.setSe
app.exec_()

【问题讨论】:

【参考方案1】:

您可以使用QListWidget 代替QListView 并覆盖itemWidget 吗?我们的想法是,这可以让您返回一个QWidget(根据您的屏幕截图带有子级),而不必实现调用每个子小部件的paint 方法的QStyledItemDelegate

【讨论】:

不,不幸的是 .setItemWidget() 和 QListWidget 不是一个选项,因为我必须使用模型/视图结构。

以上是关于使用 QStyledItemDelegates 作为 QListView 中的自定义项的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 ImagePicker 获取图像名称?我得到了图像名称,但它只在模拟器中工作,而不是在实际设备中工作

VOIP 服务不能在生产环境中工作,但在测试服务器中工作正常

MFC 中工作线程的使用

unigui作中间件使用

jquery 不在部署中工作,但在本地 nuxtjs 中工作?

为啥 EnumWindows 不能在服务中工作?