[PyQt] Suppress departure from cell in QTableView

John F Sturtz john at sturtz.org
Mon Feb 18 04:31:53 GMT 2019


Wow!  Thank you so much for all this information.  In spite of the time I have spent with PyQt, it is clear I still have much to learn.  :-/
Well, closeEditor is a signal in delegates, which is automatically connected to the closeEditor slot of the item view.
Doh!  The documentation for QAbstractItemDelegate clearly says closeEditor is a signal.  This was just a stupid oversight on my part.  [:headslap:]


A much more "elegant" way to do so would be to request the actual view from the parent argument of createEditor(); keep in mind, though, that the parent of the editor is the viewport of the view (since an item view is a QAbstractScrollArea and its contents are in an embedded "scrollable" QWidget), so the reference to the view is the parent() of the parent argument of createEditor() method, actually.
This is great!  I was looking for a way to get a reference to the view from the delegate, but I hadn't been able to find one.  Didn't look quite hard enough ...


Luckily enough, Qt's implementation correctly handles QKeyEvents of delegates and views in the right "levels". Tab navigation and return/escape keys are catched by the view, so you can take care of everything in the closeEditor() slot.
With your help, and after a bit more messing around, I have a version which seems nicely concise and reliable.  I validate input inside setModelData(), and call model.setData() if valid, but inhibit departure from the cell if not.  Then from closeEditor(), I use the same validation function, and close the editor if valid, but leave it open if not.

It seems to work for any method of cell departure, without explicitly catching mouse clicks or keystrokes.

I've attached it in case you're interested.  (For test purposes, the validation function calls any string of digits valid, and anything else not).


PS: in your code, you've been using model.setData() inside the setEditorData() method of the itemDelegate, which not only doesn't makes not much sense, but might also result in an infinite recursion.
This is a fallout of the following peculiar fact:  My actual intention is to use a QLabel as the delegate editor widget, and not a QLineEdit.  I know that seems weird, but it gives me more precise control over the editing that occurs.  (Basically, I respond to keyboard input, modify the QLabel's text, then redisplay it.  In the attached example, I changed the QLineEdit back to a QLabel, so you can see what I mean).

So the reason I called model.setData() (with a null value) inside setEditorData() was to clear out the previous cell contents.  If I didn't, the previous cell contents and the QLabel text would both display, overlapped with one another.

It turns out all I needed to do was give the QLabel an opaque background, so it just covers up the previous cell contents.  :-)

------

There is one thing in the current version that still puzzles me:  In the most recent round of messing around, I decided to subclass QLabel, and then use an object of the subclass as the editor widget rather than an actual QLabel.  And I decided to move keypress handling from eventFilter() in the delegate to keyPressEvent() in the editor widget subclass.  In the process, it seemed to change the way Tab is handled.

If you run the code as I attached it, keyboard input is handled by the delegate's eventFilter() method.  It doesn't do anything with the Tab character.  But if you hit Tab while editing, it closes the editor, moves to the next cell, and that cell is not opened for editing.

If you comment out the eventFilter() method (lines 59-81), and enable keyPressEvent() in the editor widget subclass (lines 92-112), then tabbing out of an edit field closes the editor, and opens the next field up for editing.

The latter is the default behavior for the Tab character, I believe.  But the former is actually what I want.  So it works the way I'd wish when I handle keyboard input in the delegate.  But I'm not doing anything with Tab character in either case, so it seems strange to me that in one case I'm getting one behavior, and in the other case another.


In any event, I think I'm making progress.  Thanks again for the help!  I really appreciate it.

/John
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20190217/bad09a8a/attachment-0001.html>
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: test.py
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20190217/bad09a8a/attachment-0002.ksh>
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: model.py
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20190217/bad09a8a/attachment-0003.ksh>


More information about the PyQt mailing list