解决PySide6/PyQT的界面卡死问题(PySide6/PyQT多线程

news2025/4/7 5:49:35

前言

问:在使用 PySide6 时候,会出现应用程序卡死的问题。

答:为什么会出现这个问题呢?PySide6 应用程序是基于事件驱动的,主线程负责处理GUI事件。如果有耗时的操作任务,GUI 事件将被阻塞,应用程序会处于一个假死(crash)的状态。这个时候我们是无法同应用程序进行交互,只能等待任务完成并返回结果。

本篇文章来尝试来解决这个问题。


知识点📖📖

为了避免这种情况,我们应该将长时间运行的任务移动到单独的线程中执行。
这样,既可以在后台执行任务,又能保持应用程序的响应性(不会crash

而在PySide6中,可以使用这些线程类去(QThread、QObject、QRunnable 和 QtConcurrent)创建线程多线程,并采用 信号和槽机制 来将线程中的结果回传到主线程。

本文使用QThread来做介绍,因为使用方法都大差不差(值得注意的是,QThread 继承了 QObject


关于信号和槽机制,我会再起一篇文章来对它进行介绍。


实现

下面实现一个简单窗口,用于模拟耗时的操作任务从而导致线程阻塞。

主线程阻塞

代码

以下代码是一个简单的窗口,包含一个按钮和一个标签。
当点击按钮时候,会请求10次 https://www.csdn.net/,且每次睡眠1秒,并将请求结果和请求次数在标签上逐次打印出来。

# -*- coding: utf-8 -*-


import time

import requests

from PySide6.QtCore import QSize

from PySide6.QtWidgets import (QApplication, QPushButton, QLabel, QVBoxLayout, QWidget)


class MainWindow(QWidget):

    def __init__(self, parent=None):
        super().__init__(parent=parent)
        self.setup_ui()
        #
        self.button.clicked.connect(self.setup_thread)

    def setup_ui(self):
        self.setWindowTitle('demo')
        self.resize(QSize(250, 180))
        # 创建一个垂直布局
        layout = QVBoxLayout()
        # 创建一个标签
        self.label = QLabel('This is a label => ')
        layout.addWidget(self.label)
        # 创建一个按钮
        self.button = QPushButton('Send Request')
        layout.addWidget(self.button)
        # 将布局设置为主窗口的布局
        self.setLayout(layout)
        # 显示窗口
        self.show()

    def setup_thread(self):
        for idx in range(1, 11):
            time.sleep(1)
            res = requests.get('https://www.csdn.net/').text[:15]
            self.thread_finished((idx, res))

    def thread_finished(self, item):
        self.label.setText('This is a label => ' + str(item))


if __name__ == '__main__':
    app = QApplication([])
    window = MainWindow()
    window.show()
    app.exec()

效果

窗口长这样:
在这里插入图片描述
运行效果这样:

理想的情况应该是打印10次请求次数和内容,但这里的标签只打印了第10次。很显然,这不是我们想要的。

因为有time.sleep耗时的任务,GUI 事件被阻塞,应用程序处于假死(crash)的状态。

在这里插入图片描述


使用QApplication.processEvents()

作用:用于处理当前事件队列中的所有事件,它的作用是让应用程序立即处理所有等待中的事件,并且能够让界面更加流畅,避免长时间的界面卡顿。

代码

setup_thread函数后面添加一行 QApplication.processEvents()

def setup_thread(self):
	for idx in range(1, 11):
	    time.sleep(1)
	    res = requests.get('https://www.csdn.net/').text[:15]
	    self.thread_finished((idx, res))
	    QApplication.processEvents()

效果

可以看到,现在实时打印出请求的次数和内容了!
它有用,但不是很有用!因为还有些卡顿。

请添加图片描述

使用QThread多线程

代码

这一份代码与上面的代码作用一致,区别在于它用上了多线程。

这里的 MyThread继承了QThread类,在 PySide6 中,QThread 是一个线程类,可以用来创建新线程。
这里重写了run方法,当线程的 start() 方法被调用时,就会自动执行该方法。
点击按钮会触发 setup_thread 方法,在该方法中会创建线程类 MyThread 的实例并启动该线程。

# -*- coding: utf-8 -*-

import time

import requests

from PySide6.QtCore import (QThread, Signal, Slot, QSize)
from PySide6.QtWidgets import (QApplication, QPushButton, QLabel, QVBoxLayout, QWidget)


class MyThread(QThread):
    signal_tuple = Signal(tuple)

    def __init__(self, func, *args, **kwargs):
        super().__init__()
        self.func = func
        self.args = args
        self.count: int = kwargs.get('count')

    def run(self):
        for idx in range(1, self.count + 1):
            result = self.func(*self.args)
            time.sleep(1)
            # 任务完成后发出信号
            self.signal_tuple.emit((idx, result))


class MainWindow(QWidget):

    def __init__(self, parent=None):
        super().__init__(parent=parent)
        self.setup_ui()
        #
        self.button.clicked.connect(self.setup_thread)

    def setup_ui(self):
        self.setWindowTitle('demo')
        self.resize(QSize(250, 180))
        # 创建一个垂直布局
        layout = QVBoxLayout()
        # 创建一个标签
        self.label = QLabel('This is a label => ')
        layout.addWidget(self.label)
        # 创建一个按钮
        self.button = QPushButton('Send Request')
        layout.addWidget(self.button)
        # 将布局设置为主窗口的布局
        self.setLayout(layout)
        # 显示窗口
        self.show()

    def setup_thread(self):
        self.thread_ = MyThread(self.send_request,
                                count=10,
                                label=self.label)
        self.thread_.signal_tuple.connect(self.thread_finished)
        self.thread_.start()

    def send_request(self):
        return requests.get('https://www.csdn.net/').text[:15]

    @Slot(tuple)
    def thread_finished(self, item):
        self.label.setText('This is a label => ' + str(item))


if __name__ == '__main__':
    app = QApplication([])
    window = MainWindow()
    window.show()
    app.exec()

效果

效果很完美,应用程序没有丝毫卡顿,10次请求的也逐次在标签上打印出来。

请添加图片描述

总结

多线程效果很不错!

后话

本次分享到此结束,
see you~~🐱‍🏍🐱‍🏍

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/434124.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

发送封包协议实现XXZ批量秒分解装备

通过发送封包,我们可以让一些反复的枯燥的行为变的简单,高效。 比如XXZ的萃取装备,我们可以一瞬间萃取大量的装备,而省去读条的过程。 我们来萃取一下看看效果 手动萃取是有读条的,那么如果很多装备的话,…

OAuth2.0 实践 Spring Authorization Server 搭建授权服务器 + Resource + Client

title: OAuth2.0 实践 Spring Authorization Server 搭建授权服务器 Resource Client date: 2023-03-27 01:41:26 tags: OAuth2.0Spring Authorization Server categories:开发实践 cover: https://cover.png feature: false 1. 授权服务器 目前 Spring 生态中的 OAuth2 授…

ArcGISPRO 和 ChatGPT集成思路

“我们如何一起使用 ArcGIS PRO 和 ChatGPT?”ArcGIS Pro 是一款功能强大的桌面 GIS 软件,用于制图、空间分析和数据管理。ChatGPT 是一种 AI 语言模型,可用于自然语言处理任务,例如文本生成和响应。 结合使用 ArcGIS Pro 和 Chat…

工业互联网业务知识

文章目录 背景第四次工业革命带动制造业产业升级主要工业大国不同路径 架构ISA95体系架构变革趋势基础通用架构数据采集平台 工业互联网应用软件工业互联网全要素连接产品视角:产销服务企业的业务流程企业数字化改造:车间级全要素连接 工业互联网的产品体…

Perl检查环境配置

最近部署Perl环境,但是不确定安装完成,看到有个内置监测的,记录下 perl bin/otrs.CheckModules.pl

数据类型及变量的定义、使用和注意事项

数据类型 计算机存储单元 变量的定义格式: 数据类型 变量名数据值; 我们知道计算机是可以用来存储数据的,但是无论是内存还是硬盘,计算机存储设备的最小信息单元叫“位( bit ) ",我们又称之为“比特位”,通常用…

生态-化学反应

生态,确实需要化学反应。但是如果不知道化学反应的各种前置条件,化学反应是不可能反应的。所以我们需要了解这些知识,并且把这些知识迁移到人类社会经济活动中。最厉害的人就是:范式提炼-范式迁移。 老贾就是不知道这些知识&#…

Poseidon Hash

之前我们介绍了zk友好的哈希函数Anemoi,今天我们介绍另一种zk友好的哈希函数Poseidon Poseidon采用 sponge/squeeze 结构,该结构吸纳万物并生成固定大小的输出,内部有一个状态 S ( s 1 , s 2 , . . . , s t ) S(s_1,s_2,...,s_t) S(s1​,s2…

真题详解(UML部署图)-软件设计(五十二)

真题详解(地址索引)-软件设计(五十一)https://blog.csdn.net/ke1ying/article/details/130211684 瀑布模式:适应 开发大型项目,且需求明确。 演化模式:适应 对软件需求缺乏准确认知。 螺旋模式&#xff…

C语言CRC-32 MPEG-2格式校验函数

C语言CRC-32 MPEG-2格式校验函数 CRC-32校验产生4个字节长度的数据校验码,通过计算得到的校验码和获得的校验码比较,用于验证获得的数据的正确性。基本的CRC-32校验算法实现,参考: C语言标准CRC-32校验函数 不同应用规范通过对输…

阿里JAVA架构师面试136题含答案:JVM+spring+分布式+并发编程

此文包含 Java 面试的各个方面,史上最全,苦心整理最全Java面试题目整理包括基JVM算法数据库优化算法数据结构分布式并发编程缓存等,使用层面广,知识量大,涉及你的知识盲点。要想在面试者中出类拔萃就要比人付出更多的努…

Baklib在线知识库/帮助中心:让知识无限延伸

在今天这个信息爆炸的时代,各行各业都需要一个高效的知识管理系统来帮助他们更好地组织和分享知识。Baklib在线知识库/帮助中心就是这样一个优秀的工具,它可以帮助您轻松地创建、管理和分享知识,让您的团队和客户更加高效地工作。 什么是Bakl…

Linux进程控制【进程程序替换】

✨个人主页: Yohifo 🎉所属专栏: Linux学习之旅 🎊每篇一句: 图片来源 🎃操作环境: CentOS 7.6 阿里云远程服务器 Good judgment comes from experience, and a lot of that comes from bad jud…

ESXI 6.7全面系统教程~汇总

ESXI 6.7全面系统教程 许可证:0A65P-00HD0-375M1-M097M-22P7H esxi 是一个脱机系统,也是一个虚拟机系统与vmware 相比,它可以直接运行在硬件上,这样可以减少资源浪费,一般用于服务器上;下面是esxi 的完整…

PasteSpider之服务器介绍

在PasteSpider中服务器作为重要的一个对象,编译,构建,执行等都是服务器在执行,所以如何新建和服务器的各项属性介绍尤为重要! 在菜单基础信息 服务器 点击 新增 按钮,可以看到如下图 我们从上面开始往下介…

SSR在天猫优品大促会场的探索实践

BBC 发现其网站加载时间每增加一秒,用户便会流失 10%。为提高页面的秒开率,我们不断探索着优化策略,仅仅在浏览器领域下的优化已经满足不了我们的极致要求,开始往服务端方向不断探索。本文将讨论业务接入SSR的几个问题&#xff1a…

《3-链表》

链表 引言: 存储数组需要内存空间连续,当我们需要申请一个很大的数组时,系统不一定存在这么大的连续内存空间。 而链表则更加灵活,不需要内存是连续的,只要剩余内存空间大小够用即可 1.定义 : 「链表 Lin…

设计模式-结构型模式之装饰模式

3. 装饰模式3.1. 模式动机一般有两种方式可以实现给一个类或对象增加行为:继承机制使用继承机制是给现有类添加功能的一种有效途径,通过继承一个现有类可以使得子类在拥有自身方法的同时还拥有父类的方法。但是这种方法是静态的,用户不能控制…

CSS基础——盒子模型

目录 简介 盒子模型组成 内容区 内边距 边框 border-width border-color border-style border 外边距 负值 auto 简写属性 垂直外边距的重叠 浏览器默认设置 内联元素的盒子 简介 在网页中,一切都是可以看作为“盒子”。 在css处理网页的时候&…

音游判定原理详解——从触摸屏幕到判定音符【Project SEKAI攻略】

“音乐游戏”一般简称为“音游”,玩家需要配合音乐的节奏来进行一定的动作。 《Project SEKAI》作为一个“移动端音游”,绝大多数玩家会使用手机、平板电脑等移动设备的触摸屏进行游玩,也有极少数的玩家不按常理出牌,使用手台、键…