Skip to content Skip to sidebar Skip to footer

Qt Checkbox Delegate Generates Two Checkboxes

I am trying to implement some kind of list view within a PySide GUI which gives the user the opportunity to enable/disable some entries of the list before finally processing the li

Solution 1:

You have the problem because your MyCheckBox class both is a QCheckBox (by inheritance) and also has a QCheckBox by constructing a new QCheckBox instance in its init (self.cb).

You really only want to do one or the other. Just to demonstrate, I rewrote the MyCheckBox class like this:

classMyCheckBox(QtGui.QWidget):
    def__init__(self, parent):
        QtGui.QWidget.__init__(self, parent)
        # create a centered checkbox
        self.cb = QtGui.QCheckBox(parent)
        cbLayout = QtGui.QHBoxLayout(self)
        cbLayout.addWidget(self.cb, 0, QtCore.Qt.AlignCenter)
        self.cb.clicked.connect(self.amClicked)

    clicked = QtCore.Signal()

    defamClicked(self):
        self.clicked.emit()

and this fixes the problem (though you need to make some other changes too). Note that the clicked signal you use needs to come from the MyCheckBox not the QCheckBox so I have added it to the containing class via the amClicked slot. You don't need to distinguish the data() and checked_state() methods in your model so I have merged them into one:

defdata(self, index, role=QtCore.Qt.DisplayRole):
    ifnot index.isValid():
        returnNoneelif role == QtCore.Qt.DisplayRole:
        attr_name = self.columns[index.column()]
        row = self.rows[index.row()]
        returngetattr(row, attr_name)
    elif role == QtCore.Qt.CheckStateRole:
        returnNoneelse:
        returnNone

Then the Delegate looks like this. I have arranged for it only to provide an Editor if the flags say it is editable. If not, then it is responsible for the drawing so it also has to do the correct thing in the paint method.

classCheckBoxDelegate(QtGui.QItemDelegate):
    """
    A delegate that places a fully functioning QCheckBox in every
    cell of the column to which it's applied
    """def__init__(self, parent):
        QtGui.QItemDelegate.__init__(self, parent)

    defcreateEditor(self, parent, option, index):
        ifnot (QtCore.Qt.ItemIsEditable & index.flags()):
            returnNone
        cb = MyCheckBox(parent)
        cb.clicked.connect(self.stateChanged)
        return cb

    defsetEditorData(self, editor, index):
        """ Update the value of the editor """
        editor.blockSignals(True)
        editor.setChecked(index.data())
        editor.blockSignals(False)

    defsetModelData(self, editor, model, index):
        """ Send data to the model """
        model.setData(index, editor.isChecked(), QtCore.Qt.EditRole)

    defpaint(self, painter, option, index):
        value = index.data()
        if value:
            value = QtCore.Qt.Checked
        else:
            value = QtCore.Qt.Unchecked
        self.drawCheck(painter, option, option.rect, value)
        self.drawFocus(painter, option, option.rect)

    @QtCore.Slot()defstateChanged(self):
        print"sender", self.sender()
        self.commitData.emit(self.sender())

Another approach would be to use inheritance rather than inclusion/delegation. Here's an example using that:

classMyCheckBox(QtGui.QCheckBox):
    def__init__(self, parent):
        QtGui.QCheckBox.__init__(self, parent)
        # Do some customisation here# Might want to customise the paint here# def paint(self, painter, option, index):classCheckBoxDelegate(QtGui.QItemDelegate):
    """
    A delegate that places a fully functioning QCheckBox in every
    cell of the column to which it's applied
    """def__init__(self, parent):
        QtGui.QItemDelegate.__init__(self, parent)

This seems to be more straightforward, however, in this case it has a couple of problems. It is difficult to draw the checkbox centred in the MyCheckBox class - that would need us to override the paintEvent and to do that will need careful drawing. It also will not exactly overwrite the paint of the Delegate. So you could take that out. But then it will only work if the editor has been created for the row. So the first solution is probably easiest in this case.

Post a Comment for "Qt Checkbox Delegate Generates Two Checkboxes"