4

I set my item delegates like so:

COMBOBOX_ITEMS_FRUITS = ['Apple', 'Banana']
COMBOBOX_ITEMS_COLORS = ['Red', 'Green', 'Blue']

self.treeview.setItemDelegateForColumn(COLUMN_A, ComboBoxDelegate(COMBOBOX_ITEMS_FRUITS))
self.treeview.setItemDelegateForColumn(COLUMN_B, ComboBoxDelegate(COMBOBOX_ITEMS_COLORS))

After the model is set as the source model for the proxy model, my app crashes but no errors were thrown:

self.model_source = treeview_model
self.sf_proxy_model.setSourceModel(self.model_source)

It seems that I can only use one setItemDelegateForColumn when a sortfilterproxymodel is used to process the source model.

ComboBoxDelegate is defined as follows:

class ComboBoxDelegate(QStyledItemDelegate):
    def __init__(self, items):
        super(ComboBoxDelegate, self).__init__()

        self.items = items

    def createEditor(self, parent, option, index):
        editor = QComboBox(parent)
        editor.setAutoFillBackground(True)

        for item in self.items:
            editor.addItem(item)

        return editor

    def setEditorData(self, editor, index):
        current_index = editor.findText(index.model().data(index), Qt.MatchExactly)
        editor.setCurrentIndex(current_index)

    def setModelData(self, editor, model, index):
        item_index = model.mapToSource(index)
        item = model.sourceModel().item(item_index.row(), 0)

        if index.parent().row() == -1 and item.hasChildren():
            for row in range(item.rowCount()):
                child = item.child(row, 3)
                child.setText(editor.currentText())

        model.setData(index, editor.currentText())

    def updateEditorGeometry(self, editor, option, index):
        editor.setGeometry(option.rect)
ekhumoro
  • 115,249
  • 20
  • 229
  • 336
FatHippo
  • 177
  • 3
  • 12

1 Answers1

8

The treeview does not take ownership of the delegate, so you must keep a reference to it yourself (otherwise it will be garbage-collected by python):

    self.delegate1 = ComboBoxDelegate(COMBOBOX_ITEMS_FRUITS)
    self.delegate2 = ComboBoxDelegate(COMBOBOX_ITEMS_COLORS)
    self.view.setItemDelegateForColumn(COLUMN_A, self.delegate1)
    self.view.setItemDelegateForColumn(COLUMN_B, self.delegate2)
ekhumoro
  • 115,249
  • 20
  • 229
  • 336
  • [here](http://pyqt.sourceforge.net/Docs/PyQt5/gotchas.html#garbage-collection) is the only documentation I know of for GC issues. If any one has better resource, I'd love to know about it. I find this issue inconsistent; QtLayout(self) works just fine. – hansonap Oct 16 '18 at 22:22
  • @hansonap There is no inconsistency and there are no GC issues. The [Qt documentation](https://doc.qt.io/qt-5/qabstractitemview.html#setItemDelegateForColumn) is always perfectly clear about when you need to be aware of object ownership. – ekhumoro Oct 17 '18 at 01:17
  • hmm... here are my thoughts: 1. yes, the documentation does state "QAbstractItemView does not take ownership of delegate" 2. Not taking ownership (I believe) isn't an issue for c++ and thus is a PyQt issue 3. given 2. it would be desirable for PyQt to have better docs; perhaps "keep reference if Qt docs state \"QAbstractItemView does not take ownership of delegate\"". I contacted PyQt about contributing to their docs with the hopes of providing some additional information on this topic. – hansonap Oct 17 '18 at 03:19
  • @hansonap It most definitely is relevant for C++, which is precisely why the Qt docs make a point of mentioning it. However, it is certainly not a PyQt issue as such - it's just normal Python behaviour. If you don't keep references to objects in Python, they will be garbage-collected (eventually). That has nothing to do with PyQt *per se* - it is common to all Python applications. The only "issue" here is specific to Qt: its APIs are designed for C++ and, quite understandably, take no account of other languages that may wrap their libraries. – ekhumoro Oct 17 '18 at 16:26