Search code examples
pythonlayoutpyqt4pysideqitemdelegate

Custom widget on QItemDelegate editor for QTableView


I have a QTableView showing a data from a custom model. I have a QItemDelegate for the edition on each of the cells. One column of the view has a custom widget comprised by a QLineEdit and a QCheckBox. When I click on the cells of this column the editor is shown and it works, but it doesn't fit the table cell. Moreover, when I enlarge a row and click on the cell, I can see the data of the cell behind the widget.

Is there a way that my widget behaves like a normal editing widget for a QItemDelegate on the view? i.e when created it uses all the vertical space of the cell?

This is my widget (simplified):

class MyWidget(QtGui.QWidget):
    def __init__(self, parent = None):
        super(MyWidget, self).__init__(parent)
        self.lineEdit = QtGui.QLineEdit(parent)
        self.checkBox = QtGui.QCheckBox(parent)
        self.checkBox.setChecked(False)
        self.gridLayout = QtGui.QGridLayout(self)
        self.gridLayout.setSpacing(3)
        self.gridLayout.addWidget(self.lineEdit, 0, 0)
        self.gridLayout.addWidget(self.checkBox, 0, 1)

My delegate (simplified):

class MyDelegate(QtGui.QItemDelegate):
    def __init__(self, parent = None):
        super(MyDelegate, self).__init__(parent)

    def createEditor(self, parent, option, index):
        return MyWidget(parent)

    def setModelData(self, editor, model, index):
        pass

    def setEditorData(self, editor, model, index):
        pass

Solution

  • There are a number of different problems:

    1. The vertical size-policy of a QLineEdit is fixed by default, so it will not expand to fill the availabe space.

    2. The layout has a default contents margin (i.e. padding) which may constrain the size of the contained widgets.

    3. By default, a QWidget does not draw its own background automatically, so the cell's data may be visible underneath.

    4. If the widget takes up all the space in the cell, it will no longer be possible to show that the cell is selected.

    All these problems can be fixed as follows:

    class MyWidget(QtGui.QWidget):
        def __init__(self, parent = None):
            super(MyWidget, self).__init__(parent)
            # create an inner widget
            widget = QtGui.QWidget(self)
            # disable widget transparency
            widget.setAutoFillBackground(True)
            # allow the line-edit to fully expand
            self.lineEdit = QtGui.QLineEdit(widget)
            self.lineEdit.setSizePolicy(QtGui.QSizePolicy(
                QtGui.QSizePolicy.MinimumExpanding,
                QtGui.QSizePolicy.MinimumExpanding))
            self.checkBox = QtGui.QCheckBox(widget)
            self.checkBox.setChecked(False)
            # trim space on right side of checkbox
            self.checkBox.setText('')
            hbox = QtGui.QHBoxLayout(widget)
            # remove the inner margin
            hbox.setContentsMargins(0, 0, 0, 0)
            hbox.setSpacing(3)
            hbox.addWidget(self.lineEdit)
            hbox.addWidget(self.checkBox)
            layout = QtGui.QVBoxLayout(self)
            # set the selection rectangle width
            layout.setContentsMargins(2, 2, 2, 2)
            layout.addWidget(widget)
    

    And will look like this:

    enter image description here