Home > other >  How to update listview in qml from a python QThread using list?
How to update listview in qml from a python QThread using list?

Time:06-16

I created a simple listview in qml, and I would like to update its value from a QThread using QStringListModel. I have tried several ways, but I could not really get it work. I appriciate all help. I am quite new in Qt. (Maybe I should pass the self.hosts variable value into another class?)

Here is my python code:

import os
from pathlib import Path
import sys
import PySide2.QtQml
from PySide2.QtGui import QGuiApplication
from PySide2.QtQml import QQmlApplicationEngine
from PySide2.QtCore import QObject, Slot, Signal, Property, QThread, QStringListModel

class Main(QObject):
    def __init__(self, parent=None):
        super(Main, self).__init__(parent)
        self.worker1 = Worker1()

    @Slot()
    def startCheck(self):
        self.worker1.start()

class Worker1(QThread):
    updateListView = Signal(list)
    
    def __init__(self):
        QThread.__init__(self)
        self.test_model = QStringListModel()
        self.updateListView.connect(self.updateModel)
        self.hosts = []

    def run(self):
        #Just keep it simple for test
        myList = ["A1", "A2", "A3", "A4", "B1", "B2", "B3"]
        for i in myList:
            if "A" in i:
                self.hosts.append(i)
        self.updateListView.emit(self.hosts)

    @Slot(list)
    def updateModel(self, hosts):
        self.test_model.setStringList(hosts)

    @Property(QObject, notify=updateListView)
    def model(self):
        return self.test_model

if __name__ == "__main__":

    app = QGuiApplication(sys.argv)
    engine = QQmlApplicationEngine()

    main = Main()
    engine.rootContext().setContextProperty("main", main)

    worker1 = Worker1()
    engine.rootContext().setContextProperty("worker1", worker1)

    engine.load(os.fspath(Path(__file__).resolve().parent / "main.qml"))

    if not engine.rootObjects():
        sys.exit(-1)
    sys.exit(app.exec_())

Here is my qml code:

import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Window 2.2


ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("Main Program")

    Button {
        text: qsTr("Update")
        anchors.top: parent.top
        anchors.topMargin: 21
        anchors.horizontalCenterOffset: 0
        anchors.horizontalCenter: parent.horizontalCenter
        onClicked: main.startCheck()
    }

    ListView{
        id: listView
        width: 200
        height: 150
        anchors.top: parent.top
        anchors.topMargin: 55
        anchors.horizontalCenter: parent.horizontalCenter
        contentWidth: 0
        model: worker1.model
        delegate: Text { text: display; color: "black" }
    }
}

CodePudding user response:

I have figured it out. If anyone knows a better solution, please let me know.

python code:

import os
from pathlib import Path
import sys
import PySide2.QtQml
from PySide2.QtGui import QGuiApplication
from PySide2.QtQml import QQmlApplicationEngine
from PySide2.QtCore import QObject, Slot, Signal, Property, QThread, QStringListModel

class Main(QObject):

    getUpdateModel = Signal(list)

    def __init__(self, parent=None):
        super(Main, self).__init__(parent)
        self.worker1 = Worker1()
        self.worker1.updateListView.connect(self.upDateModel)
        self.test_model = QStringListModel()


    @Slot()
    def startCheck(self):
        self.worker1.start()

    @Property(QObject, notify=getUpdateModel)
    def model(self):
        return self.test_model

    @Slot(list)
    def upDateModel(self, hosts):
        self.test_model.setStringList(hosts)


class Worker1(QThread):
    updateListView = Signal(list)

    def __init__(self):
        QThread.__init__(self)

        self.hosts = []

    def run(self):
        #Just keep it simple for test
        myList = ["A1", "A2", "A3", "A4", "B1", "B2", "B3"]
        for i in myList:
            if "A" in i:
                self.hosts.append(i)
        self.updateListView.emit(self.hosts)


if __name__ == "__main__":

    app = QGuiApplication(sys.argv)
    engine = QQmlApplicationEngine()

    main = Main()
    engine.rootContext().setContextProperty("main", main)

    engine.load(os.fspath(Path(__file__).resolve().parent / "main.qml"))

    if not engine.rootObjects():
        sys.exit(-1)
    sys.exit(app.exec_())

qml code:

import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Window 2.2


ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("Main Program")

    Button {
        text: qsTr("Update")
        anchors.top: parent.top
        anchors.topMargin: 21
        anchors.horizontalCenterOffset: 0
        anchors.horizontalCenter: parent.horizontalCenter
        onClicked: main.startCheck()
    }

    ListView{
        id: listView
        width: 200
        height: 150
        anchors.top: parent.top
        anchors.topMargin: 55
        anchors.horizontalCenter: parent.horizontalCenter
        contentWidth: 0
        model: main.model
        delegate: Text { text: display; color: "black" }
    }
}
  • Related