Nach zweitägiger Suche: Python und QT können manchmal sehr hässlich zusammenstoßen, wenn es um die Lebensdauer von Objekten geht. Folgender Code:
class MainWindow(QMainWindow):
[...]
def initTreeView(self, top_level_cats):
model = CategoryModel(top_level_cats)
self.treeview.setModel(model)
[...]
Sieht an sich erstmal unverdächtig aus: ein Model wird erzeugt (wie auch immer geartet) und dem QTreeView als Model übergeben. Scheint alles wunderbar, bis man es ausführt. Aus irgendeinem Grund bleibt der QTreeView grundsätzlich leer. Es werden zwar von dem Model unter Umständen noch einige Funktionen aufgerufen (in meinem speziellen Fall waren das headerData() und columnCount(). Keine Ahnung, ob das immer so ist), aber die eigentlich Daten werden nie dargestellt. Soweit, so schlecht.
Ein winzig kleine Änderung des Codes bringt die Lösung. Hier fast die gleiche Funktion:
class MainWindow(QMainWindow):
[...]
def initTreeView(self, top_level_cats):
self.model = CategoryModel(top_level_cats)
self.treeview.setModel(self.model)
[...]
Der einzige Unterschied: statt einer lokalen Variable ist model nun ein Feld der umgebenden Klasse. Und siehe da: plötzlich funktioniert es. Wie kommt's? (Fast) ganz einfach: man könnte zwar annehmen, dass self.treeview.setModel(...) sich das Model irgendwie speichert, wenn es noch benötigt wird, aber das scheint nicht der Fall zu sein. Anscheinend werden die entsprechenden Aufrufe nur von der dünnen Schicht von PyQt4 an die zugrundeliegende QT-Bibliothek durchgereicht und die entsprechenden Pythonobjekte dann nicht weiter beachtet. Am Ende der Funktion geht das Element im ersten Fall out-of-scope und wird dann irgendwann mal vernichtet. Blöd nur, wenn QT dann bei der Darstellung des Views plötzlich was von dem Model will, dessen Objekt zu dem Zeitpunkt nicht mehr existiert. Weißt man es hingegen einem Feld in der umgebenden Klasse (zum Beispiel dem Fenster) zu, so existiert es so lang, bis dieses vernichtet wird (und damit auch sein View). Dann kann die QT natürlich nach Herzenslust nach den Daten des Views fragen und wird immer auf unserem Model-Objekt landen, wie das gewünscht ist.
Eigentlich logisch. Wenn man's einmal weiß...