Unsolved Reset the editor of a QTableWidget instead of entering it when the editor loses focus
-
Hi :-)
I have a
QTableWidgetItem
I use aQStyledItemDelegate
on (mostly because I needed a customsetModelData
function).I would like to change the default behavior of editing, which is: The editing is finished if the user presses Enter, Return or the editor loses focus (which seems to be the default for a
QLineEdit
, according to the docs. At least, in this case, theeditingFinished
signal is emitted). I don't want the data to be comitted on focus loss, only on Enter/Return pressing.So I created my own
QLineEdit
derived editor and implemented a customcreateEditor
function in the delegate, using this one.Ifirst tried to reimplement the editor's
focusOutEvent
, where I set the entered text back to the initial value before passing the event to the base class. Problem is thatsetModelData
is called before thefocusOutEvent
function.I then tried to reimplement the whole
event
function and looked for something to happen earlier. The first thing I found wasevent->type()
to beQEvent::aboutToChangeFocus
, but even with this one,setModelData
is called earlier.I also tried to figure out how the editor is connected to the delegate and at which very point
setModelData
is invoked. But I didn't find it (those Qt sources are quite complicated sometimes :-( at least for a hobby programmer like I am).So is there any way to change this? One can break this down into the question: How can I know if the editor was closed via pressing Enter/Return or via focus loss?
Thanks for all help!
-
Set a breakpoint in setModelData() and take a look at the backtrace to see from where it is called.
-
@Christian-Ehrlicher I'm not sure I'm fit enough with this stuff but I tried it ;-)
Apparently,
setModelData
is called viaQAbstractItemDelegate::commitData(QWidget*)
, but I still don't know how it works …Question is if I need to know how the internals work, as I only want to handle the
editingFinished
signal (I suppose) and decide, based on if Enter/Return has been pressed or the focus was lost, if I reset or commit the data … -
@l3u_ said in Reset the editor of a QTableWidget instead of entering it when the editor loses focus:
but I still don't know how it works …
You should not know how it works you should take a look at the backtrace to see from where it is triggered - somewhere the text must be read from the QLineEdit which is nearby the place you can jump in.
-
@Christian-Ehrlicher Apparently, I just can't read it?!
#0 0x00005555556783de in PlayersPageDelegate::setModelData(QWidget*, QAbstractItemModel*, QModelIndex const&) const () #1 0x00007ffff7a8f325 in QAbstractItemView::commitData(QWidget*) () from /usr/lib64/libQt5Widgets.so.5 #2 0x00007ffff7a8e480 in ?? () from /usr/lib64/libQt5Widgets.so.5 #3 0x00007ffff6f5daae in QMetaObject::activate(QObject*, int, int, void**) () from /usr/lib64/libQt5Core.so.5 #4 0x00007ffff7aa8adf in QAbstractItemDelegate::commitData(QWidget*) () from /usr/lib64/libQt5Widgets.so.5 #5 0x00007ffff7aa9845 in ?? () from /usr/lib64/libQt5Widgets.so.5 #6 0x00007ffff7aa99a8 in ?? () from /usr/lib64/libQt5Widgets.so.5 #7 0x00007ffff6f5e66a in QObject::event(QEvent*) () from /usr/lib64/libQt5Core.so.5 #8 0x00007ffff7841501 in QApplicationPrivate::notify_helper(QObject*, QEvent*) () from /usr/lib64/libQt5Widgets.so.5 #9 0x00007ffff7848af8 in QApplication::notify(QObject*, QEvent*) () from /usr/lib64/libQt5Widgets.so.5 #10 0x00007ffff6f358a1 in QCoreApplication::notifyInternal2(QObject*, QEvent*) () from /usr/lib64/libQt5Core.so.5 #11 0x00007ffff6f389c6 in QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*) () from /usr/lib64/libQt5Core.so.5 #12 0x00007ffff6f86763 in ?? () from /usr/lib64/libQt5Core.so.5 #13 0x00007ffff5b046fd in g_main_context_dispatch () from /usr/lib64/libglib-2.0.so.0 #14 0x00007ffff5b04998 in ?? () from /usr/lib64/libglib-2.0.so.0 #15 0x00007ffff5b04a2c in g_main_context_iteration () from /usr/lib64/libglib-2.0.so.0 #16 0x00007ffff6f86503 in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) () from /usr/lib64/libQt5Core.so.5 #17 0x00007ffff6f34873 in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) () from /usr/lib64/libQt5Core.so.5 #18 0x00007ffff6f3c482 in QCoreApplication::exec() () from /usr/lib64/libQt5Core.so.5 #19 0x00005555556034c6 in main ()
Seems like it's called by
QAbstractItemDelegate::commitData
, but I can't override it in my delegate ("… is marked as override but doesn't")? [Edit:] Okay, that's because it's a signal, not a function. -
Seems like I still don't understand what you want to achieve - you don't want to commit the data when the focus changes, or why do you try to fiddle around with the focus event?
You want to commit the data when enter is pressed - then you have to watch for Qt::KeyEnter in the QLineEdit::keyPressEvent() and then emit QAbstractItemDelegate::commitData() - this is what's done for the focusOut/ChangeEvent as you can see in the backtrace. -
@Christian-Ehrlicher If Enter/Return is pressed in the editor, the data should be comitted. Just as it's the case now. But if the editor loses focus, nothing should happen, the editing should be aborted. Per default, if I click somewhere outside the editor (after having changed something), it's the same as if I pressed Enter/Return.
The problem is that I don't know what to change to achieve this and where to change it (in a custom editor or the delegate) … also, I don't know at which point which signals from the editor are connected to the delegate.
What I don't understand is: If the
focusOutEvent
causeseditingFinshed
to be emitted which finally causescommitData
to be emitted andsetModelData
to be called, then why issetModelData
called before I seefocusOutEvent
being called?! -
Okay. I worked around it. I implemented a custom
QLineEdit
used by the delegate with:void PlayersEditor::keyPressEvent(QKeyEvent *event) { if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) { m_enterPressed = true; } QLineEdit::keyPressEvent(event); }
and
bool PlayersEditor::enterPressed() const { return m_enterPressed; }
And in my
QStyledItemDelegate
'ssetModelData
, I simply doif (! m_editor->enterPressed()) { return; }
Which leaves the model unchanged and "just" closes the editor. Maybe not the "right" way, but it works …
Edit: Just to mention this: one has to declare m_editor as mutable to be able tol set it inside
createEditor
, as this function is const. -
Hi,
Out of curiosity, why do you want that behavior ?
It's kind of counter intuitive with regard to how applications work with that kind of editing feature.
-
@SGaist The table widget I use is not intended to be used like a spread sheet (LibreOffice or Excel). It's a list of names with additional columns one can trigger actions on. And normally, one doesn't edit the name, as long as one doesn't see a typo or such in it.
So clicking outside the edited name item is either a mistake or a "oh, I wanted to do something else before". So I think, for my use-case, it's better to have the user to confirm an edit action by pressing Enter or Return rather than clicking somewhere outside the editor.
Maybe a corner-case ;-)