1

I want to design a custom ListView widget which has custom items similar to this: https://i.stack.imgur.com/iTNbN.png

However, the qt documentation and some stackoverflow posts state that one should ideally use a QStyleItemDelegate. I never worked with 'delegates' before but as far as I understood from my research they are called by the ListView for drawing / rendering each item.

I found a delegate example in another project (https://github.com/pyblish/pyblish-lite/blob/master/pyblish_lite/delegate.py) and they draw everything by hand / are essentially rebuilding entire widgets by painting rectangles.

This seems a bit impractical for me as most of the time custom item widgets can be compounds of existing widgets. Take a look at the screenshot above. It essentially contains a Qlabel, QPixmap, and four DoubleSpinBoxes.

Question: How would you use the painting / rendering methods that already exist in them instead of manually painting everything on your own? That way you can profit from existing member methods and can use layouts for structuring your widget.

For example the first ListViewItem should pass the model data to the delegate so that the text of the self.lightGroupName QLabel can be set to "Light1".

Any help is greatly appreciated, since I have no idea how to go on from here:

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 Answers1

0

Instead of QListView, could you use QListWidget and override itemWidget? The idea would be that this lets you return a QWidget (with children as per your screenshot) instead of having to implement a QStyledItemDelegate that calls each child widget's paint method.

Michael Herrmann
  • 4,832
  • 3
  • 38
  • 53