Solved QItemDelegate for editing questions
-
I have written my first
QItemDelegate
subclass to allow editing of a certain kind of data in aQTableView
. My code works fine, but I'm a touch uneasy about a couple of issues. I'd appreciate any comments.Code is Python/PyQt, but don't let that put you C++ers off reading! It's really simple and close to C++.
I need to allow user to edit dates in a column. I have already rolled my own
QWidget
for that,JDateEdit
, used elsewhere in my app. Before anyone asks, can't use Qt'sQDateEdit
for that as it does not allow the date to be left empty --- I asked here about that a long time ago. Not relevant to the issues anyway. Also, I looked intoQItemEditFactory
and the example using that: decided not to go down that route, it uses Qt properties and C++ macros to accomplish and those are just a pain from Python/PyQt. So I am just doing it via subclassingQItemDelegate
. With this said, onto the code:Caller:
self.tableView.setModel(self.model) self.tableView.setItemDelegateForColumn(col, JDateItemDelegate(self.tableView))
Subclass definition:
class JDateItemDelegate(QItemDelegate): # delegate to provide a JDateEdit for editing a date nicely when it's in e.g. a JTableView def __init__(self, parent=None): super().__init__(parent) def createEditor(self, parent: QWidget, option: QStyleOptionViewItem, index: QModelIndex): return JDateEdit(parent) def setEditorData(self, dateEdit: JDateEdit, index: QModelIndex): date = index.model().data(index, Qt.EditRole) dateEdit.setDate(date) def setModelData(self, dateEdit: JDateEdit, model: QAbstractItemModel, index: QModelIndex): date = dateEdit.date() model.setData(index, date)
That's it! I'd appreciate comments on:
-
Have I done anything wrong/missed anything?
-
Qt is usually very precise/consistent in the parameters etc. it uses.
setModelData()
has amodel
parameter which I use formodel.setData()
to store the data back. ButsetEditorData()
does not have amodel
parameter: I still need to fetch the data to edit frommodel.data()
, so I've had to get the model viaindex.model()
(which could equally have been done insetModelData()
). Why this inconsistency between the two methods --- am I missing something? -
createEditor()
is passed aQModelIndex
parameter but I don't use it, perhaps because I know I've only set my delegate on an appropriate column so I don't need to check? I don't seem to need to fetch the value to edit from the model here, assetEditorData()
will be called upon edit and that's where I will be doing it? -
createEditor()
is passed aQStyleOptionViewItem
parameter. I don't use it because I don't know what to do with it. Now, very specifically, while I was Googling earlier to find about all of this, I came across a post which I cannot now find. It said/warned to the effect of: "if you are creating your own editor widget, you should set Qt hard focus on your widget, as otherwise some events intended for your editor may go to the table view, or vice versa". Where I have written Qt hard focus it was actually some Qt attribute, something about "hard" & "focus", perhaps some style for aQWidget
? Can anyone figure what it was, because I cannot find the reference again for the life of me?
Many thanks for any answers.
-
-
First please derive from QStyledItemDelegate, QItemDelegate will hopefully go away with Qt6.
- setEditorData()/setModelData() - you forgot QModelIndex::data() which can be used in setEditorData() as a shortcut.
- createEdtior() - it's because you can create a different editor/widget for each index
- QStyleOptionViewItem - just take a look at the parameters - it's used for drawing the item so you can use it too if you want/need it.
The stuff with the hard focus I don't understand...
-
@Christian-Ehrlicher
Thanks, that's perfect. I will change my derivation.you forgot
QModelIndex::data()
which can be used insetEditorData()
as a shortcut.Funny you should say that! Earlier I was musing to myself: "If
QModelIndex
contains a reference to the model, then a convenience method to access the data would be possible...". :) That's good, but doesn't to me answer why Qt passes the model explicitly tosetModelData()
but not tosetEditorData()
. It's as though they expect you to need it in the former but not in the latter, so I wondered if I was missing something.I still wonder what that Qt hard focus thing I saw is about.... Does a widget have some "hard focus" property which affects how it receives events?
-
Maybe they mean StrongFocus?
-
@Christian-Ehrlicher
You're a hero :)
Here we go https://doc.qt.io/qt-5/qabstractitemdelegate.html:The returned editor widget should have
Qt::StrongFocus
; otherwise,QMouseEvents
received by the widget will propagate to the view.What do you think of that? Do I need to take any action on the
QWidget
I am returning? -
At least I did not yet had problems with the default behavior but it maybe depends on the type of the displayed widget - with QComboBoxes I don't have a problem here.
-
@Christian-Ehrlicher
OK, mine too seems to be working without my doing anything aboutStrongFocus
so I won't worry. -
@JonB said in QItemDelegate for editing questions:
but doesn't to me answer why Qt passes the model explicitly to setModelData() but not to setEditorData()
index.model()
returns aconst QAbstractItemModel*
you can read the data from the model and set it inside the editor but you can't performs actions that alter the model from it, that's whysetModelData()
needs to have another, non-const, model passed as argument -
@VRonin
Ahhhhh!!!!! Well, that makes sense. I wouldn't know that, because I'm Python/PyQt where we don't have any notion ofconst
and we can change whatever we like when we like, regardless! :) -
@JonB said in QItemDelegate for editing questions:
Python/PyQt where we don't have any notion of const and we can change whatever we like when we like
A truly frightening thought....
-
@J.Hilk Everything about Python is frightening.... :)