qtpyqtqtableviewqtreeviewqabstractitemview

qt permanently display delegate in view


How do you use QStyledItemDelegate / QItemDelegate to permanently display a complex widget, i.e. to handle the Qt.DisplayRole, not just Qt.EditRole?

The documentation eludes to using paint()... but that's just way to complex! Let's take for example rendering a QTreeView or QTableVeiw inside of a QTableView cell.

There is QAbstractItemView.setIndexWidget(), but that is a bad idea as it only used to display static content (and whats the fun in static models?).

Note

I found part of the answer in another post, but it was only a small subset of the answer, so I thought it warranted a new post with proper question.


Solution

  • The key is to use QAbstractItemView.openPersistentEditor() to always keep the cell in edit mode.

    Some additional key elements

    1. The Qt.EditRole flag will need to be provided for the cells which use delegates.
    2. QStyledItemDelegate.sizeHintChanged.emit(index) needs to be called anytime the size of the editor widget has changed.
    3. Implementing QStyledItemDelegate.sizeHint() can be tricky and tedious (or you can do index.internalPointer().editor_widget.sizeHint() assuming you saved a reference of the editor to the internal pointer during QStyledItemDelegate.createEditor()

    Caution

    It should be mentioned that opening editors is costly, so if you have thousands of indexes and they are all loaded at once, it can take a while. There are many ways to mitigate this issue:

    1. Load the model incrementally using a thread
    2. Use Qt's fetchMore() mechanism
    3. call openPersistentEditor incrementally (using a timer, or as they come into view for the first time)
    4. call openPersistentEditor when the parent is expanded and closePersistentEditor when the parent is collapsed, and possibly restrict the use of expand-all on nodes with many children.