pyqt5 子线程如何操作主线程GUI

news/2024/11/19 17:22:23/文章来源:https://www.cnblogs.com/lihongtaoya/p/18197784

一.简介

在使用pyqt5编写gui时遇到两个问题,会导致界面崩溃,今天就围绕这两个问题来简单说明和改进。

1.在主线程中使用while无限循环会导致界面崩溃

2.在子线程中操作主线程gui会导致界面崩溃

二.步骤说明

1.在主线程中使用while无限循环会导致界面崩溃

1)错误代码

import sysfrom PyQt5.QtWidgets import  QPushButton, QTextEdit, QApplication, QHBoxLayout, QWidgetclass FileChooserApp(QWidget):def __init__(self):super().__init__()self.initUI()def initUI(self):button = QPushButton("按钮")self.reviewEdit = QTextEdit()self.reviewEdit.move(100, 100)button.clicked.connect(self.send)hbox1 = QHBoxLayout()  # 创建一个水平布局hbox1.addWidget(button)  # 添加按钮到水平布局中hbox1.addStretch(1)  # 设置水平比例间距hbox1.addWidget(self.reviewEdit)  # 添加按钮到水平布局中
self.setLayout(hbox1)  # 添加到布局器self.setWindowTitle('文件选择器')self.setGeometry(300, 300, 500, 500)def send(self):"""事件:return:"""while True:"""逻辑代码"""self.reviewEdit.setText("测试")if __name__ == '__main__':app = QApplication(sys.argv)ex = FileChooserApp()ex.show()sys.exit(app.exec_())
View Code

2)崩溃原因

我们先来说下while崩溃的问题,这边我设置的循环是一个无限循环,不会给 GUI 事件循环任何运行的机会。在 PyQt 或其他 GUI 框架中,GUI 的事件循环(例如按钮点击、窗口移动等)必须在单独的线程中运行,以保持 GUI 的响应性

3)改进方法

将循环体在一个子线程中执行,就可以避免这个问题,代码如下。

import sys
import threadingfrom PyQt5.QtWidgets import QPushButton, QTextEdit, QApplication, QHBoxLayout, QWidgetclass FileChooserApp(QWidget):def __init__(self):super().__init__()self.initUI()def initUI(self):button = QPushButton("按钮")self.reviewEdit = QTextEdit()self.reviewEdit.move(100, 100)button.clicked.connect(self.send)hbox1 = QHBoxLayout()  # 创建一个水平布局hbox1.addWidget(button)  # 添加按钮到水平布局中hbox1.addStretch(1)  # 设置水平比例间距hbox1.addWidget(self.reviewEdit)  # 添加按钮到水平布局中
self.setLayout(hbox1)  # 添加到布局器self.setWindowTitle('文件选择器')self.setGeometry(300, 300, 500, 500)def send(self):"""事件:return:"""def send_a():while True:"""逻辑代码"""print("123")send_thread = threading.Thread(target=send_a)# 启动线程
        send_thread.start()if __name__ == '__main__':app = QApplication(sys.argv)ex = FileChooserApp()ex.show()sys.exit(app.exec_())
View Code

2.在子线程中操作主线程gui会导致界面崩溃

1)错误代码

import sys
import threading
import timefrom PyQt5.QtWidgets import QPushButton, QTextEdit, QApplication, QHBoxLayout, QWidgetclass FileChooserApp(QWidget):def __init__(self):super().__init__()self.initUI()def initUI(self):button = QPushButton("按钮")self.reviewEdit = QTextEdit()self.reviewEdit.move(100, 100)button.clicked.connect(self.send)hbox1 = QHBoxLayout()  # 创建一个水平布局hbox1.addWidget(button)  # 添加按钮到水平布局中hbox1.addStretch(1)  # 设置水平比例间距hbox1.addWidget(self.reviewEdit)  # 添加按钮到水平布局中
self.setLayout(hbox1)  # 添加到布局器self.setWindowTitle('文件选择器')self.setGeometry(300, 300, 500, 500)def send(self):"""事件:return:"""def send_a():while True:"""逻辑代码"""self.reviewEdit.setText("设置文案")send_thread = threading.Thread(target=send_a)# 启动线程
        send_thread.start()if __name__ == '__main__':app = QApplication(sys.argv)ex = FileChooserApp()ex.show()sys.exit(app.exec_())
View Code

2)崩溃原因

上述中试图在子线程send_a方法中给文本编辑器设置文案。这是不允许的,因为 PyQt 和大多数 GUI 框架一样,要求所有的 GUI 更新必须在主线程(也称为 GUI 线程)中执行。

3)改进方法

既然在子线程中无法操作主线程gui更新,那么只能在主线程中去执行,这就需要信号与槽的配合了。我们先来自定义一个信号

class YourThread(QObject):show_warning_signal = pyqtSignal()def run(self):self.show_warning_signal.emit()

在初始化的时候去实例化YourThread类,连线信号与槽

class FileChooserApp(QMainWindow):def __init__(self):super().__init__()self.initUI()self.your = YourThread()self.your.show_warning_signal.connect(self.settext)

接着在子线程中直接去触发信号即可

    def send(self):def send_a():while True:"""循环体"""self.your.run()time.sleep(2)send_thread = threading.Thread(target=send_a)# 启动线程send_thread.start()

执行每次循环需要等待2s,避免出现无限循环导致应用程序冻结、响应缓慢或其他线程相关的问题

三.实例

import sys
import threading
import timefrom PyQt5.QtCore import QObject, pyqtSignal
from PyQt5.QtWidgets import QPushButton, QTextEdit, QApplication, QHBoxLayout, QWidgetclass YourThread(QObject):show_warning_signal = pyqtSignal()def run(self):self.show_warning_signal.emit()class FileChooserApp(QWidget):def __init__(self):super().__init__()self.initUI()self.your = YourThread()self.your.show_warning_signal.connect(self.settext)def initUI(self):button = QPushButton("按钮")self.reviewEdit = QTextEdit()self.reviewEdit.move(100, 100)button.clicked.connect(self.send)hbox1 = QHBoxLayout()  # 创建一个水平布局hbox1.addWidget(button)  # 添加按钮到水平布局中hbox1.addStretch(1)  # 设置水平比例间距hbox1.addWidget(self.reviewEdit)  # 添加按钮到水平布局中
self.setLayout(hbox1)  # 添加到布局器self.setWindowTitle('文件选择器')self.setGeometry(300, 300, 500, 500)def send(self):"""事件:return:"""def send_a():while True:"""逻辑代码"""self.your.run()time.sleep(2)send_thread = threading.Thread(target=send_a)# 启动线程
        send_thread.start()def settext(self):self.reviewEdit.setText("123")if __name__ == '__main__':app = QApplication(sys.argv)ex = FileChooserApp()ex.show()sys.exit(app.exec_())

 

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

BOSHIDA AC/DC电源模块的设计与优化

BOSHIDA AC/DC电源模块的设计与优化 AC/DC电源模块是一种将交流电转换为直流电的设备,广泛应用于各种电子设备中。其设计与优化对于提高电源的效率、稳定性以及可靠性非常重要。在设计与优化AC/DC电源模块时,需要考虑以下几个方面。 首先,设计AC/DC电源模块需要选择合适的开…

Applescript实现无痕检测是否注册iMessage服务,iMessages数据筛选,iMessage蓝号检测完美实现

一、实现iMessage蓝号数据筛选的两种方式:1.人工筛选,将要验证的号码输出到文件中,以逗号分隔。再将文件中的号码粘贴到iMessage客户端的地址栏,iMessage客户端会自动逐个检验该号码是否为iMessage账号,检验速度视网速而定。红色表示不是iMessage账号,蓝色表示iMessage账号…

SSRF攻击

SSRF服务端请求伪造目录SSRF攻击原理漏洞利用redis未授权访问访问漏洞进行攻击SSRF绕过方式SSRF中URL的伪协议SSRF漏防御手段 SSRF攻击 服务端请求伪造 原理 事故多发地在url分享、收藏、网址翻译功能。 参数通常是:(其实就是参数值是另一个url的地方就有可能有SSRF) share li…

函数计算帮助领健为“看牙”注入AI活力

作者:姜伟,龚杨,周韬,王彬 客户介绍和业务背景 领健成立于2015年,总部位于上海,并在全国设立了20余家分支机构,拥有100项软件著作权、91项注册商标、35项发明专利,致力为口腔诊所、医美机构等消费医疗企业提供经营管理一体化解决方案。 领健拥有 ISO/IEC27001 国内国际…

【Linux】《VMware17搭建Ubuntu.22.04-Rust开发环境》

下载VMware17安装包 下载链接: 创建虚拟机之后都默认就可以了。进入系统设置登录账号和密码以及修改下语言,剩余都默认即可。 设置中文界面设置中文输入法接下来开始设置输入法切换快捷键设置 使用 Ctrl + Alt + T 打开终端,输入 ibus-setup重启,看一下是否有输入法信息尝试…

多线程下使用List中的subList和remove方法产生的 java.util.ConcurrentModificationException 异常

在说多线程操作List之前,我们先看下单线程下产生的问题: 单线程List<Integer> listA=new ArrayList<>(); listA.add(1); listA.add(2); listA.add(3); listA.add(4); listA.add(5); listA.add(6);for(Integer a:listA…

KubeKey v3.1 发布:快速自定义离线安装包

日前,KubeKey v3.1 正式发布。该版本主要对离线场景部署、离线包制作以及向 Kubernetes v1.24+ 升级进行了优化。 KubeKey 简介KubeKey 是 KubeSphere 社区开源的一款高效集群部署工具,运行时默认使用 Docker,也可对接 Containerd、CRI-O、iSula 等 CRI 运行时,且 ETCD 集群…

DashVector + ModelScope 玩转多模态检索

本教程演示如何使用向量检索服务(DashVector),结合ModelScope上的中文CLIP多模态检索模型,构建实时的“文本搜图片”的多模态检索能力。作为示例,我们采用多模态牧歌数据集作为图片语料库,用户通过输入文本来跨模态检索最相似的图片。 整体流程主要分为两个阶段: 图片数…

element-plus table部分列根据接口返回key展示

实现效果根据刷选年份返回对应年份作为部分列1. 处理接口数据接口返回数据格式需要处理成   处理过程data.message && data.message.forEach((item:any)=>{let obj = {}for(var key in item){if(Number(key)){Object.assign(obj, {[key]: item[key]})}item.data =…

设计模式05----适配器模式

适配器模式: 适配器模式(Adapter Pattern)是一种结构型设计模式,它允许不兼容的接口协同工作。这种模式涉及到一个单独的类,该类负责将一个类的接口转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以一起工作。 例如: USB转接口就是适配器,它能够将各种不同类…

基于时间的断路器

1 新建一个微服务模块 我们在cloud-payment-service模块中新增一个controller以提供给其它微服务模块调用。 @RestController public class PayCircuitController {@GetMapping("/pay/circuit/{id}")public String myCircuit(@PathVariable("id") Integer …