I am trying to dynamically populate a QML ComboBox from the Python backend (PySide6) with, first, a set of default values, and, on clicking a button, a second set of values.
I'm trying to do this by setting the ComboBox's model attribute in the QML to a QStringListModel property (cbxItems
) initially containing the default values in the backend. On receiving the signal that the button has been clicked, the code would update the property with the second set of values.
The problem is, with both sets, although the model appears to have been successfully populated with items as evidenced by getting and printing the model's string list, the combobox remains empty (no items appear in the popup nor the combobox itself)
Here's a minimal reproducible example:
main.py:
import sys
from PySide6.QtCore import QObject, QStringListModel, QUrl, Slot
from PySide6.QtGui import QGuiApplication
from PySide6.QtQml import QQmlApplicationEngine
class Backend(QObject):
@Slot()
def doUpdateCbx(self):
self.cbxItems.setStringList([str(i) for i in range(4, 7)])
print(self.cbxItems.stringList())
def __init__(self, parent=None):
super().__init__(parent)
self.cbxItems = QStringListModel()
self.cbxItems.setStringList([str(i) for i in range(1, 4)])
print(self.cbxItems.stringList())
if __name__ == "__main__":
app = QGuiApplication(sys.argv)
backend = Backend()
engine = QQmlApplicationEngine()
engine.rootContext().setContextProperty("manager", backend)
engine.load(QUrl.fromLocalFile("main.qml"))
if not engine.rootObjects():
sys.exit(-1)
sys.exit(app.exec())
main.qml
import QtQuick 6.5
import QtQuick.Controls 6.5
import QtQuick.Layouts 6.5
import QtQuick.Window 6.5
ApplicationWindow {
title: qsTr("Test")
width: 640
height: 480
visible: true
ColumnLayout {
id: colLayout
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.right: parent.right
ComboBox {
model: manager.cbxItems
Layout.fillWidth: true
delegate: Text { text: model.display }
}
Button {
id: updateButton
width: 200
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
text: "Update Combobox"
onClicked: {
manager.doUpdateCbx()
}
}
}
Connections {
target: manager
}
}
When I click on the combobox this is what appears empty combobox
On running main.py
the contents of cbxItems
is logged correctly (["1", "2", "3"]
), the same on clicking the button (["4", "5", "6"]
). This seems to point that the string list in cbxItems
has been successfully changed, yet somehow the changes made to it is not reflecting on the combobox?
I'm aware the example above is relatively simple and probably doable from QML alone, but I would have to populate both sets of values dynamically in the real application from a long-running function run on a separate thread so as not to freeze the UI.
Help, anyone? What am I missing?