Qt Checkbox Delegate Generates Two Checkboxes
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"