How to invoke QStyledItemDelegate::setModelData when using custom editors?
-
Hello everyone!
I'm using QPushButton as editor and I want to call QStyledItemDelegate::setModelData overrode method each time the button is clicked. So here is my code:
QWidget* CEditorDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem&, const QModelIndex& index) const { //... connect(pButton, &QPushButton::clicked, this, &CEditorDelegate::CommitData); } void CEditorDelegate::CommitData() { QPushButton* editor = qobject_cast<QPushButton*>(sender()); if (!editor) return; emit commitData(editor); } void CEditorDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const { //... model->setData(index, data, Qt::EditRole); }But I see that
setModelDatais never called. What am I doing wrong?
I am also surprised that even here I saw an approach withstd::bindinconnect, so in my case that would beconnect(pButton, &QPushButton::clicked, this, std::bind(&QStyledItemDelegate::commitData, this, pButton));But in fact it won't work, because
QStyledItemDelegate::createEditorisconst, so it looks like I am doing something wrong with my non-constCommitDatamethod even if it's called due to successful connection.My code is based on this topic, for example:
QStyledItemDelegate with Custom Widget: setModelData function never gets called -
B bibasmall deleted this topic on
-
B bibasmall restored this topic on
-
@James-Gallegos said in How to invoke QStyledItemDelegate::setModelData when using custom editors?:
is that you are not emitting the commitData signal from your CommitData method.
But the OP has always shown he does do that.
Here's how you can modify your CommitData method to emit the commitData signal:
void CEditorDelegate::CommitData() { QPushButton* editor = qobject_cast<QPushButton*>(sender()); if (!editor) return; emit commitData(editor); // emit the commitData signal }This is precisely what the OP showed he currently has, character for character.
@JonB
In addition to my previous post —setModelDatais called with such connects, so it seems withsender()I just abused a bug.connect(pButton, &QPushButton::clicked, this, std::bind(&CEditorDelegate::CommitData, const_cast<CEditorDelegate*>(this), pButton)); //or connect(pButton, &QPushButton::clicked, [nonConstThis = const_cast<CEditorDelegate*>(this), pButton]() { nonConstThis->CommitData(pButton); });Actually I don't understand how do I customise editors behaviour more elegantly (considering
const_casta bad practise), since most of the QStyledItemDelegate methods are constant while signals are not. -
Hello everyone!
I'm using QPushButton as editor and I want to call QStyledItemDelegate::setModelData overrode method each time the button is clicked. So here is my code:
QWidget* CEditorDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem&, const QModelIndex& index) const { //... connect(pButton, &QPushButton::clicked, this, &CEditorDelegate::CommitData); } void CEditorDelegate::CommitData() { QPushButton* editor = qobject_cast<QPushButton*>(sender()); if (!editor) return; emit commitData(editor); } void CEditorDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const { //... model->setData(index, data, Qt::EditRole); }But I see that
setModelDatais never called. What am I doing wrong?
I am also surprised that even here I saw an approach withstd::bindinconnect, so in my case that would beconnect(pButton, &QPushButton::clicked, this, std::bind(&QStyledItemDelegate::commitData, this, pButton));But in fact it won't work, because
QStyledItemDelegate::createEditorisconst, so it looks like I am doing something wrong with my non-constCommitDatamethod even if it's called due to successful connection.My code is based on this topic, for example:
QStyledItemDelegate with Custom Widget: setModelData function never gets called@bibasmall said in How to invoke QStyledItemDelegate::setModelData when using custom editors?:
But I see that
setModelDatais never called. What am I doing wrong?You use
QPushButton* editor = qobject_cast<QPushButton*>(sender());. I would never usesender(). Have you verified what that is returning? Ifsender()isnullptror not aQPushButton*you won'temit commitData(editor). -
@bibasmall said in How to invoke QStyledItemDelegate::setModelData when using custom editors?:
But I see that
setModelDatais never called. What am I doing wrong?You use
QPushButton* editor = qobject_cast<QPushButton*>(sender());. I would never usesender(). Have you verified what that is returning? Ifsender()isnullptror not aQPushButton*you won'temit commitData(editor).@JonB
What would you use instead ofsender()?
The other way I see here isconst_cast<CEditorDelegate*>(this)inCEditorDelegate::createEditor, what is really ugly.@JonB said in How to invoke QStyledItemDelegate::setModelData when using custom editors?:
Have you verified what that is returning?
I did, I see that
commitDatais actually emitted in debugger. -
The reason why the
setModelDatamethod is not being called is that you are not emitting thecommitDatasignal from yourCommitDatamethod. ThecommitDatasignal is what triggers thesetModelDatamethod in the delegate. Therefore, you need to emit this signal from yourCommitDatamethod.Here's how you can modify your
CommitDatamethod to emit thecommitDatasignal:void CEditorDelegate::CommitData() { QPushButton* editor = qobject_cast<QPushButton*>(sender()); if (!editor) return; emit commitData(editor); // emit the commitData signal }Regarding your use of
std::bindin theconnectstatement, it is unnecessary and can be replaced with a lambda function that calls theCommitDatamethod directly. Theconstqualifier on thecreateEditormethod is not relevant here, as you are not trying to modify the object's state within the method.Here's an example of how you can modify the
connectstatement to use a lambda function:connect(pButton, &QPushButton::clicked, this, [this, pButton]() { CommitData(); });This lambda function captures
thisandpButtonby value, and calls theCommitDatamethod when the button is clicked. -
@JonB
What would you use instead ofsender()?
The other way I see here isconst_cast<CEditorDelegate*>(this)inCEditorDelegate::createEditor, what is really ugly.@JonB said in How to invoke QStyledItemDelegate::setModelData when using custom editors?:
Have you verified what that is returning?
I did, I see that
commitDatais actually emitted in debugger.@bibasmall
sender()became unnecessary when new styleconnect()syntax allowing C++ lambdas for slots was introduced a decade ago.connect(pButton, &QPushButton::clicked, this, [this, pButton]() { CommitData(pButton); } ); void CEditorDelegate::CommitData(QPushButton *btn) { }I'm not sure about why your
emit commitData(editor)does not causesetModelData()to be called. When I did editing delegates I did notemit commitData(editor)and I did not have another widget like a button to conclude editing. I just overrodesetEditorData()&setModelData(), and it all just "worked". -
The reason why the
setModelDatamethod is not being called is that you are not emitting thecommitDatasignal from yourCommitDatamethod. ThecommitDatasignal is what triggers thesetModelDatamethod in the delegate. Therefore, you need to emit this signal from yourCommitDatamethod.Here's how you can modify your
CommitDatamethod to emit thecommitDatasignal:void CEditorDelegate::CommitData() { QPushButton* editor = qobject_cast<QPushButton*>(sender()); if (!editor) return; emit commitData(editor); // emit the commitData signal }Regarding your use of
std::bindin theconnectstatement, it is unnecessary and can be replaced with a lambda function that calls theCommitDatamethod directly. Theconstqualifier on thecreateEditormethod is not relevant here, as you are not trying to modify the object's state within the method.Here's an example of how you can modify the
connectstatement to use a lambda function:connect(pButton, &QPushButton::clicked, this, [this, pButton]() { CommitData(); });This lambda function captures
thisandpButtonby value, and calls theCommitDatamethod when the button is clicked.@James-Gallegos said in How to invoke QStyledItemDelegate::setModelData when using custom editors?:
is that you are not emitting the commitData signal from your CommitData method.
But the OP has always shown he does do that.
Here's how you can modify your CommitData method to emit the commitData signal:
void CEditorDelegate::CommitData() { QPushButton* editor = qobject_cast<QPushButton*>(sender()); if (!editor) return; emit commitData(editor); // emit the commitData signal }This is precisely what the OP showed he currently has, character for character.
-
@bibasmall
sender()became unnecessary when new styleconnect()syntax allowing C++ lambdas for slots was introduced a decade ago.connect(pButton, &QPushButton::clicked, this, [this, pButton]() { CommitData(pButton); } ); void CEditorDelegate::CommitData(QPushButton *btn) { }I'm not sure about why your
emit commitData(editor)does not causesetModelData()to be called. When I did editing delegates I did notemit commitData(editor)and I did not have another widget like a button to conclude editing. I just overrodesetEditorData()&setModelData(), and it all just "worked".@JonB
The reason why I usedsender()is on the screenshot — my code won't compile if I call the non-const method for constthis.

Somehow it compiles when CommitData has no arguments and the connection looks like this (so that's why I get the pointer to the editor fromsender()):connect(pButton, &QPushButton::clicked, this, &CEditorDelegate::CommitData);Though I'm sure it's a bug and it shouldn't compile for the same qualifier reason.
I've used the same approach before to force QCombobox close right after selecting an option, so I emitted two signals:emit commitData(editor); emit closeEditor(editor);And I had no problem with invoking
setModelData. But for a buttonsetModelDatais just silently not called. I see that the signal is emitted after I click the button, but no reaction after. -
@James-Gallegos said in How to invoke QStyledItemDelegate::setModelData when using custom editors?:
is that you are not emitting the commitData signal from your CommitData method.
But the OP has always shown he does do that.
Here's how you can modify your CommitData method to emit the commitData signal:
void CEditorDelegate::CommitData() { QPushButton* editor = qobject_cast<QPushButton*>(sender()); if (!editor) return; emit commitData(editor); // emit the commitData signal }This is precisely what the OP showed he currently has, character for character.
@JonB
In addition to my previous post —setModelDatais called with such connects, so it seems withsender()I just abused a bug.connect(pButton, &QPushButton::clicked, this, std::bind(&CEditorDelegate::CommitData, const_cast<CEditorDelegate*>(this), pButton)); //or connect(pButton, &QPushButton::clicked, [nonConstThis = const_cast<CEditorDelegate*>(this), pButton]() { nonConstThis->CommitData(pButton); });Actually I don't understand how do I customise editors behaviour more elegantly (considering
const_casta bad practise), since most of the QStyledItemDelegate methods are constant while signals are not. -
@JonB
The reason why I usedsender()is on the screenshot — my code won't compile if I call the non-const method for constthis.

Somehow it compiles when CommitData has no arguments and the connection looks like this (so that's why I get the pointer to the editor fromsender()):connect(pButton, &QPushButton::clicked, this, &CEditorDelegate::CommitData);Though I'm sure it's a bug and it shouldn't compile for the same qualifier reason.
I've used the same approach before to force QCombobox close right after selecting an option, so I emitted two signals:emit commitData(editor); emit closeEditor(editor);And I had no problem with invoking
setModelData. But for a buttonsetModelDatais just silently not called. I see that the signal is emitted after I click the button, but no reaction after.@bibasmall
I'm not understanding what is going on with yourconstor not. The slotCommitData()must not beconst. Is it??Hmm, you mean you call it from
CEditorDelegate::createEditor(), that isconst, so itsthisisconst, and you can't then use that for the slot object? Then I really don't know why it's OK for theconnect()to actual slot but not to lambda (I suspect it's this issue, not because the newCommitData(QPushButton *btn)parameter....Is your
CommitData()const? Doesn't look like it. If you made itconstdoes that allow theconnect()?UPDATE
I think this has crossed with your latest. I believe you show there you have found a way. I prefer the second one.Basically you have raised a "gotcha":
createEditor()isconst, and that prevents you from connecting a slot tothisinside it, which is something one might well want to do. It (apparently) works when&CEditorDelegate::CommitDatais passed on its own as a standalone argument, but not if you try a lambda withthis->CommitData(). If the C++ super-experts here see this they might comment.... -
B bibasmall has marked this topic as solved on