Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Reset the editor of a QTableWidget instead of entering it when the editor loses focus



  • Hi :-)

    I have a QTableWidgetItem I use a QStyledItemDelegate on (mostly because I needed a custom setModelData 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, the editingFinished 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 custom createEditor 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 that setModelData is called before the focusOutEvent function.

    I then tried to reimplement the whole event function and looked for something to happen earlier. The first thing I found was event->type() to be QEvent::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!


  • Lifetime Qt Champion

    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 via QAbstractItemDelegate::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 …


  • Lifetime Qt Champion

    @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.


  • Lifetime Qt Champion

    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 causes editingFinshed to be emitted which finally causes commitData to be emitted and setModelData to be called, then why is setModelData called before I see focusOutEvent 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's setModelData, I simply do

    if (! 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.


  • Lifetime Qt Champion

    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 ;-)


Log in to reply