You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PySide2中如何通过Python QThread用列表更新QML ListView

问题核心错误

你的代码无法运行是3个逻辑问题导致的:

  • 重复创建Worker1实例:Main类初始化时生成了一个self.worker1,主函数中又新建了一个worker1暴露给QML。点击按钮启动的是Main内部的Worker线程,QML的ListView绑定的是主函数里从未启动过的Worker的model,两个对象完全独立,数据无法同步。
  • Qt模型线程归属违规:QStringListModel属于UI相关对象,必须存活在主线程,放在QThread子类中跨线程操作极易触发随机崩溃。
  • 属性通知逻辑失效:model属性绑定的notify信号和实际模型更新操作不匹配,QML无法感知模型数据变化,自然不会刷新视图。

你不需要额外把self.hosts变量传到其他类,修正实例归属和线程逻辑即可正常运行。

修正后的Python代码
import os
from pathlib import Path
import sys
from PySide2.QtGui import QGuiApplication
from PySide2.QtQml import QQmlApplicationEngine
from PySide2.QtCore import QObject, Slot, Signal, Property, QThread, QStringListModel

class Worker1(QThread):
    # 线程仅负责发送计算完成的列表数据,不持有、不操作任何UI模型
    updateListView = Signal(list)
    
    def run(self):
        # 测试用业务逻辑
        myList = ["A1", "A2", "A3", "A4", "B1", "B2", "B3"]
        hosts = []
        for i in myList:
            if "A" in i:
                hosts.append(i)
        # 跨线程发送结果,Qt会自动把信号排队到主线程执行
        self.updateListView.emit(hosts)

class Main(QObject):
    modelChanged = Signal()
    def __init__(self, parent=None):
        super(Main, self).__init__(parent)
        # 模型放在主线程实例中,仅在主线程操作
        self._model = QStringListModel()
        self.worker1 = Worker1()
        # 绑定线程更新信号到主线程的模型更新槽
        self.worker1.updateListView.connect(self.updateModel)

    @Property(QObject, notify=modelChanged)
    def model(self):
        return self._model

    @Slot()
    def startCheck(self):
        # 防止重复点击启动多个相同线程
        if not self.worker1.isRunning():
            self.worker1.start()

    @Slot(list)
    def updateModel(self, hosts):
        self._model.setStringList(hosts)
        # 数据更新后发送通知,触发QML视图刷新
        self.modelChanged.emit()

if __name__ == "__main__":
    app = QGuiApplication(sys.argv)
    engine = QQmlApplicationEngine()

    main = Main()
    # 仅需暴露main实例给QML,无需单独暴露worker对象
    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代码
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.horizontalCenter: parent.horizontalCenter
        onClicked: main.startCheck()
    }

    ListView{
        id: listView
        width: 200
        height: 150
        anchors.top: parent.top
        anchors.topMargin: 55
        anchors.horizontalCenter: parent.horizontalCenter
        // 绑定主线程main对象中的model
        model: main.model
        delegate: Text { 
            text: model.display 
            color: "black"
            width: listView.width
            horizontalAlignment: Text.AlignHCenter
        }
    }
}
关键改动说明
  • 移除重复的Worker1实例:全局仅保留一个Worker对象挂在Main类下,保证按钮启动的线程、信号绑定的线程是同一个对象。
  • 调整模型归属:把QStringListModel从QThread子类移到主线程的Main类中,所有模型操作都在主线程执行,符合Qt UI相关对象仅能在主线程操作的强制规则,避免跨线程崩溃。
  • 修复属性通知:模型数据更新后主动触发modelChanged信号,QML绑定的ListView会自动响应数据变化刷新内容。
  • 线程逻辑解耦:Worker线程只负责执行耗时计算,计算完成后通过跨线程信号把结果抛给主线程,线程本身不操作任何UI相关对象,符合Qt多线程开发规范。
  • 增加线程运行状态判断:防止重复点击按钮启动多个相同线程造成资源泄漏。
  • 移除了原QML中无效的contentWidth: 0配置,避免列表内容显示不全。

内容的提问来源于stack exchange,提问作者rolando_cser

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 23:16:31