HowTo: QML ComboBox mit einem Custom ListModel

Otrek Wilke
3 min readAug 22, 2020

Qt, QtQuick und Python/ PySide2

Wie kann eine QComboBox mit einem QAbstactListModel verbunden werden?

In einer meiner letzten Apps die ich entwickelte, habe ich mich dazu entschieden nicht Qt und PyQt zu nutzen, sondern PySide2 und QML. Wieso? graphisch sieht QML irgendwie moderner aus, out of the box. Und es bietet auch einen anderen Zugang zu graphisch ansprechenden Anwendungen.

Basisarbeiten für die Demo

Als erstes benötigen wir eine Python Datei und eine QML Datei die das Fontend implementiert.

Der komplette Code findet sich auf GitHub

Im Frontend betten wird eine ComboBox und zwei Buttons einfach in ein Rechteck in einem Window ein. Das Model wird über den Namen stringModel angesprochen.

In der Pythondatei wird die QApplication zum Starten der Anwendung und die QQmlApplicationEngine zur Darstellung des Frontends benötigt.

Die Funktionalitäten des Fontends sind in einem Bridge genannten QObject implementiert, dieses wird dem Context der QmlApplicationEngine als property bekannt gemacht. Ebenso das Datenmodel, welches ein Attribute der Bridge ist.

Darauf die Grundlage zu erstellen gehe ich hier nicht näher ein, vielmehr soll es hier drum gehen wie das Model zur ComboBox kommt. Wenn ihr mehr zu den Anfängen lesen wollt schreibts in die Kommentare.

Nutzen eines QStringListModels für Stringlisten

Bei der Entwicklung der App entstand die Herausforderung eine ComboBox, also ein DropDown Element dynamisch mit Inhalten zu bestücken. Qt/Qml bietet hier die Möglichkeit ein (Daten)Model zu hinterlegen. Mit einem QStringListModel funktioniert das ganz einfach.

Dieses Model kann an der Bridge einfach als Attribute exponiert werden. Anschließend können über insertRow und setData Daten dem Model hinzugefügt werden, bzw. über deleteRow auch Daten entfernt werden.

Im QML Modell wird das Model einfach ans model Attribute der ComboBox angehangen

Nutzen eines QAbstractListModel um mehr Daten zu verwalten

Da es sich bei den Inhalten nicht nur um Strings, sondern auch gleich um ganze Objekte handelte wollte ich ein Custom Model auf Basis des QAbstractListModels verwenden. Gesagt getan, funktioniert nur nicht so wie gewünscht. Wenn Daten über insertRows (Achtung, die Variante mit s) und setData hinzugefügt werden, dann wird die Länge der DropDown Liste nicht aktualisiert.

Des Rätsels Lösung ist es die insertRow Methode zu verwenden und mehrere Rows über eine Schleife hinzuzufügen.

Ein minimales Model basierend auf dem QAbstractListModel , welches auch dynamisches Hinzufügen und Entfernen ermöglicht, implementiert also die Methoden:

  • rowCount
  • Data
  • setData
  • insertRow

Alle anderen Funktionen können aus dem original übernommen werden.

Daten dem Modell hinzufügen

Wie auch immer die Daten in die App kommen, hier in dem ein String hinzugefügt wird, dies kann aber auch ein beliebiges Python Objekt sein.

Durch klick auf den Button “Add One” wird die Funktion bridge.add_one() ausgeführt. Hier wird dem Modell eine neue Zeile hinzugefügt und anschließend der Inhalt dieser neuen Zeile über setData geändert.

Wenn es sich bei den Daten nicht nur um ein String handelt, sondern um ein Objekt, dann kann dieses mittel der Qt.UserRole und der data Methode des Models auch wieder aufgerufen werden. Das QListModel übernimmt damit für uns die Verwaltung der Indexe und Daten.

Der vollständige Quellcode kann gefunden werden unter:

ComboBox mit QStringListModel:

https://github.com/JimKnopf2034/PySideQListModels/releases/tag/StringListModel

ComboBox mit QAbstractListModel:

https://github.com/JimKnopf2034/PySideQListModels/releases/tag/AbstractListModel

Wann nutzt ihr QML und Python? Benutzt ihr ComboBoxen um variablen Inhalt zur Auswahl zu stellen? Wollt ihr mehr über die Nutzung von QML und Python wissen? Schreibt’s in die Kommentare!

Findest du das hilfreich? Dann lass doch ein Clap da oder:

--

--

Otrek Wilke

Data Engineering made easy. Writing about things learned in data engineering, data analytics, and agile product development.