首页 > 其他分享 >pyqt5 子线程如何操作主线程GUI

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

时间:2024-05-17 14:53:25浏览次数:12  
标签:__ hbox1 GUI send 线程 pyqt5 self def

一.简介

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

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

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

二.步骤说明

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

1)错误代码

import sys

from PyQt5.QtWidgets import  QPushButton, QTextEdit, QApplication, QHBoxLayout, QWidget


class 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 threading

from PyQt5.QtWidgets import QPushButton, QTextEdit, QApplication, QHBoxLayout, QWidget


class 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 time

from PyQt5.QtWidgets import QPushButton, QTextEdit, QApplication, QHBoxLayout, QWidget


class 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 time

from PyQt5.QtCore import QObject, pyqtSignal
from PyQt5.QtWidgets import QPushButton, QTextEdit, QApplication, QHBoxLayout, QWidget


class 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_())

 

标签:__,hbox1,GUI,send,线程,pyqt5,self,def
From: https://www.cnblogs.com/lihongtaoya/p/18197784

相关文章

  • 多线程下使用List中的subList和remove方法产生的 java.util.ConcurrentModificationEx
    在说多线程操作List之前,我们先看下单线程下产生的问题:单线程List<Integer>listA=newArrayList<>();listA.add(1);listA.add(2);listA.add(3);listA.add(4);listA.add(5);listA.add(6);for(Integera:listA){......
  • Java-线程-wait()、notify()和notifyAll()
    0.是什么(What)wait(),notify(),和notifyAll()方法都是Object类的一部分,用于实现线程间的协作。1.为什么(Why)线程的执行顺序是随机的(操作系统随机调度的,抢占式执行),但是有时候,我们希望的是它们能够顺序的执行。所以引入了这几个方法,使得我们能保证一定的顺序。1.1Objec类......
  • 美团面试:如何实现线程任务编排?
    线程任务编排指的是对多个线程任务按照一定的逻辑顺序或条件进行组织和安排,以实现协同工作、顺序执行或并行执行的一种机制。1.线程任务编排VS线程通讯有同学可能会想:那线程的任务编排是不是问的就是线程间通讯啊?线程间通讯我知道了,它的实现方式总共有以下几种方式:Object......
  • 「Pygors跨平台GUI」1:Pygors跨平台GUI应用研究
    「Pygors系列」一句话导读:Python、Go、Rust、C程序跨平台GUI框架研究。 一、问题Pygors是什么?Pygors是我自己创造的一个词,就是Python、Go、Rust、C四种语言的合体。目的是为了跨平台GUI应用。至于说怎么多了个C语言,那是因为前三种语言都与C语言有密切的关系,C语言无所不在。......
  • 「Pygors跨平台GUI」2:安装MinGW-w64、MSYS2还是WSL2
    「Pygors系列」一句话导读:MinGW-w64只有编译器,MSYS2带着更新环境,WSL2实用性比较高 历史与渊源  Windows平台Linux平台二进制兼容WSL2:运行Linux程序Wine:运行Windows程序接口兼容CygWin:编译Linux程序Winelib:编译Windows程序编译器兼容MinGW-w64:编译Linux......
  • 进程、线程和协程之间的区别和联系
    文章目录一、进程二、线程三、进程和线程的区别与联系四、一个形象的例子解释进程和线程的区别五、进程/线程之间的亲缘性六、协程一、进程进程,直观点说,保存在硬盘上的程序运行以后,会在内存空间里形成一个独立的内存体,这个内存体有自己独立的地址空间,有自己的堆,上级挂靠单......
  • 避免DbContext同时在多个线程调用
    下面这个微软官方文档阐述了,应该避免在多个线程上同时操作同一个DbContext:AvoidingDbContextthreadingissues其中有说到,在使用DbContext的代码中,所有的异步函数应该立即被await,否则会有极大概率抛出InvalidOperationException。这是因为一个DbContext实例不能被多个线程同时......
  • 超线程/同步多线程(HT/SMT)技术
    超线程/同步多线程(HT/SMT)技术虽然现在超线程(Hyper-Threading)被大家广泛接受,并把所有一个物理核心上有多个虚拟核心的技术都叫做超线程,但这其实是Intel的一个营销名称。而实际上这一类技术的(学术/技术)通行名称是同步多线程(SMT,SimultaneousMultithreading)技术。SMT技术初衷是通......
  • Java-线程-synchronized
    0.背景文章目录层级较多,参考我这篇文章来进行展开,方便阅读:博客园SimpleMemory主题如何浮动目录显示参考文章:synchronized底层monitor原理synchronized的底层是基于Java的监视器monitor的。在Java中,monitor(监视器)是用来实现线程同步的一种基本机制。它是一个控制结构,内置......
  • Qt 中用Q_GLOBAL_STATIC来实现线程安全的单例模式
    官方说明:Qt中有个宏Q_GLOBAL_STATIC可以用来创建一个全局静态变量,下面看下官方文档的说明:Q_GLOBAL_STATIC(Type,VariableName)CreatesaglobalandstaticobjectoftypeQGlobalStatic,ofnameVariableNameandthatbehavesasapointertoType.Theobjectcr......