PDA

View Full Version : Problem with custom QStyledItemDelegate and tab handling



d_stranz
14th April 2020, 19:07
I have implemented a custom QStyledItemDelegate for editing a cell in a QTableView. The delegate's editor is a QWidget with some radio buttons and two line edits. See the attached screenshots that show the editor widget as a delegate and parented with a QDialog.

The problem I am having is when the editor is used as a delegate. If I edit the text in either line edit and then press Tab, the editor is immediately closed. The new text is discarded and control goes back to the table view.

When used in a QDialog, the behavior is normal; Tab moves the focus to the next widget in the tab chain.

I have installed an event filter on both line edits and watch for FocusOut events. In delegate mode, editing one line edit and then -clicking- on the next generates a focus out event on the first line edit. Editing the first line edit and pressing Tab does not generate a focus out event.

I have tried setting window modality to Qt::ApplicationModal when using the editor as a delegate. This has no effect on behavior, even though the delegate reports that the editor "isModal" in all of the delegate methods (setEditorData(), setModelData(), updateEditorGeometry() etc.).

How do I make this editor behave like a modal dialog when used as a delegate? In other words, the user must be forced to click either Ok or Cancel to close the delegate? Do I need to install an event filter on the table view and intercept tabs when the delegate is active?

13382 13383

EDIT: Installing an event filter on the table view has no effect. After reading more of the QStyledItemDelegate docs, I see that it puts an event filter on the editor which intercepts the Tab key. Overriding this implementation in my derived delegate class has no effect, so it is likely the base class is getting the event first. If I explicitly install my own event filter on the editor class immediately after creating it, there is still no effect, so again, the base class must be getting it first.

Ginsengelf
15th April 2020, 07:37
Hi, maybe creating the event filter later might help:
From https://doc.qt.io/qt-5/qobject.html#installEventFilter:

If multiple event filters are installed on a single object, the filter that was installed last is activated first.

Ginsengelf

d_stranz
15th April 2020, 15:50
Thanks, I have tried that. I have event filters everywhere - on the line edits, on the widget that contains them, on the delegate itself. I can see the Tab come in (as a QKeyEvent of type Qt:ShortcutOverride), but I can't seem to stop if from propagating and closing the editor. I have overridden eventFilter() on the delegate class (which should force mine to be used instead of the QStyledItemDelegate regardless of which one is installed last). I have even overridden event() on the editor widget to try to trap the event there. Nothing seems to work.

I discovered the problem by accident. My QLineEdit widgets have a QDoubleValidator installed on them to force entry of a double in a specific range. In this case, the QLineEdit::editingFinished() signal is not emitted (so the docs say, but why not?). I was editing and the data were never stored in the underlying data structure. That's when I discovered my slot was not being called. The other QLineEdit signals are emitted for every character, so they can't be used to retrieve a final value. So I added an event filter on the QLineEdit instances to trap the FocusOut events, and this worked as a substitute for handling editingFinished(). Until I discovered that when I hit Tab to move from one line edit to the next, I never got the FocusOut event on the first line edit.

I have wasted two days on this so far. I am about to throw it in, make the column in the table view read only, and add a tool tip telling the user if they want to change this field, click the Edit button that lets then edit the whole row in a dialog. Not great, since every other column can be edited in-place, but time is money.