当前位置: 首页 > news >正文

Pyside6 + QML - 多线程01 - QThread 基础(子线程执行耗时任务)

导言


在现代图形化应用程序中,用户界面的流畅性至关重要。尤其是在需要执行耗时任务时,如何保证UI的响应性成为开发者的一大挑战。PySide6 提供了强大的多线程支持,使得开发者能够将耗时的计算任务放入后台线程中执行,从而避免阻塞主线程的 UI 响应。

在这一章节中,将介绍如何使用 QThread 来在子线程中执行耗时任务,同时利用信号机制将任务结果安全地传递回UI线程。通过这种方式,应用程序能够在执行后台任务的同时保持界面的高响应性,提升用户体验。我们将通过具体示例,展示如何使用 Worker + QThread 模式,轻松实现这一功能。

效果如下:
在这里插入图片描述
工程代码:

  • github: https://github.com/q164129345/myPyside6_QML/tree/main/thread01_begin
  • gitee: https://gitee.com/wallace89/myPyside6_QML/tree/main/thread01_begin

一、main.py


# python3.10.11 - PySide6==6.9
import sys, time
from PySide6.QtCore import QObject, Signal, Slot, QThread
from PySide6.QtGui import QGuiApplication
from PySide6.QtQml import QQmlApplicationEngineclass Worker(QObject):finished = Signal(str) # 定义线程结束信号,传递字符串参数def run(self):for i in range(5):print(f"[Python] 线程运行中... {i+1}/5")time.sleep(1)  # 模拟耗时操作self.finished.emit("任务完成!来自子线程")  # 任务完成,发射信号class Backend(QObject):resultReady = Signal(str)  # 定义信号,传递字符串参数def __init__(self):super().__init__() # 初始化父类self.thread = Noneself.worker = None@Slot()def startTask(self):# 创建子线程和Worker对象self.thread = QThread()self.worker = Worker()self.worker.moveToThread(self.thread)  # 将Worker对象移到子线程# 线程启动->调用worker的run方法self.thread.started.connect(self.worker.run)  # 线程启动时调用Worker的run方法# worker完成-> 发信号给UIself.worker.finished.connect(self.resultReady.emit)  # 将结果通过信号传递# worker完成->退出线程self.worker.finished.connect(self.thread.quit)self.worker.finished.connect(self.worker.deleteLater)  # 任务完成后删除worker对象self.thread.finished.connect(self.thread.deleteLater)  # 线程结束后删除线程对象self.thread.start()  # 启动线程print("[Backend] 子线程已启动...")if __name__ == "__main__":# 创建应用程序和引擎app = QGuiApplication(sys.argv)engine = QQmlApplicationEngine()# qml与python交互backend = Backend() # 实例化python后端对象engine.rootContext().setContextProperty("backend", backend) # 注册到QML环境(名叫 “backend”)# 加载QML文件engine.addImportPath(sys.path[0])  # 当前项目路径engine.loadFromModule("Example", "Main")  # 模块(Example) + QML文件名(Main.qml)if not engine.rootObjects():sys.exit(-1)sys.exit(app.exec())

关键点说明

@Slot()
def startTask(self):# 创建子线程和Worker对象self.thread = QThread()self.worker = Worker()self.worker.moveToThread(self.thread)  # 将Worker对象移到子线程# 线程启动->调用worker的run方法self.thread.started.connect(self.worker.run)  # 线程启动时调用Worker的run方法# worker完成-> 发信号给UIself.worker.finished.connect(self.resultReady.emit)  # 将结果通过信号传递# worker完成->退出线程self.worker.finished.connect(self.thread.quit)self.worker.finished.connect(self.worker.deleteLater)  # 任务完成后删除worker对象self.thread.finished.connect(self.thread.deleteLater)  # 线程结束后删除线程对象self.thread.start()  # 启动线程print("[Backend] 子线程已启动...")

这几行是 QThread + Worker 模式的标准写法
它们的作用是:建立信号和槽的连接,保证子线程能正确启动、退出、清理。

  • self.thread = QThread():新建一个线程对象(还没真正跑起来)。给耗时任务准备一个独立执行环境,避免卡住 UI。

  • self.worker = Worker():创建执行耗时任务的对象。把耗时逻辑集中到 Worker.run(),便于复用与测试。注意:Worker 必须无父对象,才允许迁移到其它线程。

  • self.worker.moveToThread(self.thread) :把 Worker 所属线程切换到 self.thread。确保之后通过信号/事件驱动调用到的 Worker 槽函数在子线程执行。只改变“线程亲和性”,不会自动调用 run()

  • self.thread.started.connect(self.worker.run):当线程事件循环真正启动时,自动调用 worker.run()。保证 run() 在子线程里执行(这行配合上面的 moveToThread 实现)。这是跨线程连接,Qt 会自动使用 Queued Connection

  • self.worker.finished.connect(self.resultReady.emit) :把 Workerfinished(str) 直接转发Backend.resultReady(str)。把结果抛回主线程给 QML;这是常用的“信号转信号”写法。finished 在子线程发出,但 resultReady 会在主线程排队处理,UI 安全。

  • self.worker.finished.connect(self.thread.quit):任务一完成,通知线程退出事件循环。不用的线程应尽快停掉,避免一直空转占资源。

  • self.worker.finished.connect(self.worker.deleteLater):标记 Worker 为“稍后删除”(由 Qt 事件循环安全回收)。避免立即 del 引发跨线程销毁风险;deleteLater 会在其所属线程安全清理。很多示例也会用 self.thread.finished.connect(self.worker.deleteLater),两者都常见;
    你的写法在 quit() 前发出删除事件,也会被安全处理。

  • self.thread.finished.connect(self.thread.deleteLater):线程真正结束后,安全销毁 QThread 对象本身。彻底释放资源,避免“僵尸线程”或内存泄漏。

  • self.thread.start(): 启动子线程事件循环 → 触发上面的 started 信号 → worker.run() 开始干活。一定要先连接好所有信号再 start(),否则可能错过 started

二、Main.qml


// 导入QtQuick模块,提供基本的QML元素
import QtQuick
// 导入QtQuick.Controls模块,提供UI控件如Button
import QtQuick.Controls// 定义一个窗口组件,作为应用程序的主窗口
Window {// 设置窗口宽度width: 320// 设置窗口高度height: 240// 设置窗口可见visible: true// 设置窗口标题title: "多线程01 - 基础示例"// 使用Column布局,垂直排列子元素Column {// 将Column居中对齐到父元素(窗口)anchors.centerIn: parent// 设置子元素之间的间距spacing: 20// 定义一个按钮Button {// 设置按钮文本text: "开始耗时任务"// 定义按钮点击事件处理函数onClicked: {// 调用backend对象的startTask方法,开始任务backend.startTask()// 更新结果文本为“任务进行中...”resultText.text = "任务进行中..."}}// 定义一个文本元素,用于显示结果Text {// 设置文本元素的ID,用于在代码中引用id: resultText// 设置初始文本text: "等待结果..."// 设置字体大小font.pointSize: 18}}// 使用Connections对象来连接信号和槽Connections {// 设置目标对象为backendtarget: backend// 定义信号处理函数,当backend发出resultReady信号时调用function onResultReady(msg) {// 更新结果文本为信号传递的消息resultText.text = msg}}
}

qml代码看注释吧,很简单。

http://www.dtcms.com/a/399874.html

相关文章:

  • 农产品应该建设哪个网站屏幕分辨率 网站开发
  • 摄影作品展示网站flash全站源码山东住建部和城乡建设官网
  • 购物网站功能模块图使用div建设的网站
  • Python爬虫实战:获取上海石油天然气交易中心2025年液化天然气交易数据并做分析
  • springboot项目添加请求url及请求入参日志
  • Spring XML 配置简介
  • 阿里云虚拟主机如何上传网站国外flash网站
  • NXP - 安装后的MCUXpresso IDE里面有所有的支持包,不用另外去下载
  • 公司网站域名更改怎么做做美团旅游网站多少钱
  • 网站建设初稿wordpress 教學
  • 【nvm for windows安装问题】手动安装方案
  • 网站定制开发怎么写网站后台管理系统图片
  • 如何本地搭建网站贵阳市门户网站
  • 网站设计理念怎么写wordpress插件清理
  • 语义精炼技巧生成对抗网络(3)基于Wasserstein GAN 的特征生成
  • 3.算法——遗传算法
  • html怎么做网站版块网站空间购买官方
  • 成都建站网站软件开发涵盖网站开发吗
  • DDOS高防的优点是什么
  • 电子电气架构 --- 引导式诊断
  • 视觉大模型:Qwen-VL 技术报告解读
  • 给公司建立网站不可以做到的是素材下载网站开发文档
  • wordpress网站类型长春网页设计培训
  • 半精度浮点在AI推理中的应用:C++23新类型与性能测试
  • p-SCN-Bn-NOTA,1206475-68-4是一种双功能螯合剂用于金属离子螯合
  • 62.[前端开发-Vue3]Day04-jsconfig-Vue版本-组件间通信-插槽
  • 珠海建设集团网站首页扬州网络科技有限公司网站建设
  • 微网站开发 mui框架大城 网站
  • 使用aspx做电影网站东莞做个网站
  • 彩投网站建设做网站抄代码