翼度科技»论坛 编程开发 python 查看内容

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

5

主题

5

帖子

15

积分

新手上路

Rank: 1

积分
15
一.简介

在使用pyqt5编写gui时遇到两个问题,会导致界面崩溃,今天就围绕这两个问题来简单说明和改进。
1.在主线程中使用while无限循环会导致界面崩溃
2.在子线程中操作主线程gui会导致界面崩溃
二.步骤说明

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

1)错误代码
  1. import sys
  2. from PyQt5.QtWidgets import  QPushButton, QTextEdit, QApplication, QHBoxLayout, QWidget
  3. class FileChooserApp(QWidget):
  4.     def __init__(self):
  5.         super().__init__()
  6.         self.initUI()
  7.     def initUI(self):
  8.         button = QPushButton("按钮")
  9.         self.reviewEdit = QTextEdit()
  10.         self.reviewEdit.move(100, 100)
  11.         button.clicked.connect(self.send)
  12.         hbox1 = QHBoxLayout()  # 创建一个水平布局
  13.         hbox1.addWidget(button)  # 添加按钮到水平布局中
  14.         hbox1.addStretch(1)  # 设置水平比例间距
  15.         hbox1.addWidget(self.reviewEdit)  # 添加按钮到水平布局中
  16.         self.setLayout(hbox1)  # 添加到布局器
  17.         self.setWindowTitle('文件选择器')
  18.         self.setGeometry(300, 300, 500, 500)
  19.     def send(self):
  20.         """
  21.         事件
  22.         :return:
  23.         """
  24.         while True:
  25.             """
  26.             逻辑代码
  27.             """
  28.             self.reviewEdit.setText("测试")
  29. if __name__ == '__main__':
  30.     app = QApplication(sys.argv)
  31.     ex = FileChooserApp()
  32.     ex.show()
  33.     sys.exit(app.exec_())
复制代码
View Code2)崩溃原因
我们先来说下while崩溃的问题,这边我设置的循环是一个无限循环,不会给 GUI 事件循环任何运行的机会。在 PyQt 或其他 GUI 框架中,GUI 的事件循环(例如按钮点击、窗口移动等)必须在单独的线程中运行,以保持 GUI 的响应性
3)改进方法
将循环体在一个子线程中执行,就可以避免这个问题,代码如下。
  1. import sys
  2. import threading
  3. from PyQt5.QtWidgets import QPushButton, QTextEdit, QApplication, QHBoxLayout, QWidget
  4. class FileChooserApp(QWidget):
  5.     def __init__(self):
  6.         super().__init__()
  7.         self.initUI()
  8.     def initUI(self):
  9.         button = QPushButton("按钮")
  10.         self.reviewEdit = QTextEdit()
  11.         self.reviewEdit.move(100, 100)
  12.         button.clicked.connect(self.send)
  13.         hbox1 = QHBoxLayout()  # 创建一个水平布局
  14.         hbox1.addWidget(button)  # 添加按钮到水平布局中
  15.         hbox1.addStretch(1)  # 设置水平比例间距
  16.         hbox1.addWidget(self.reviewEdit)  # 添加按钮到水平布局中
  17.         self.setLayout(hbox1)  # 添加到布局器
  18.         self.setWindowTitle('文件选择器')
  19.         self.setGeometry(300, 300, 500, 500)
  20.     def send(self):
  21.         """
  22.         事件
  23.         :return:
  24.         """
  25.         def send_a():
  26.             while True:
  27.                 """
  28.                 逻辑代码
  29.                 """
  30.                 print("123")
  31.         send_thread = threading.Thread(target=send_a)
  32.         # 启动线程
  33.         send_thread.start()
  34. if __name__ == '__main__':
  35.     app = QApplication(sys.argv)
  36.     ex = FileChooserApp()
  37.     ex.show()
  38.     sys.exit(app.exec_())
复制代码
View Code2.在子线程中操作主线程gui会导致界面崩溃

1)错误代码
  1. import sys
  2. import threading
  3. import time
  4. from PyQt5.QtWidgets import QPushButton, QTextEdit, QApplication, QHBoxLayout, QWidget
  5. class FileChooserApp(QWidget):
  6.     def __init__(self):
  7.         super().__init__()
  8.         self.initUI()
  9.     def initUI(self):
  10.         button = QPushButton("按钮")
  11.         self.reviewEdit = QTextEdit()
  12.         self.reviewEdit.move(100, 100)
  13.         button.clicked.connect(self.send)
  14.         hbox1 = QHBoxLayout()  # 创建一个水平布局
  15.         hbox1.addWidget(button)  # 添加按钮到水平布局中
  16.         hbox1.addStretch(1)  # 设置水平比例间距
  17.         hbox1.addWidget(self.reviewEdit)  # 添加按钮到水平布局中
  18.         self.setLayout(hbox1)  # 添加到布局器
  19.         self.setWindowTitle('文件选择器')
  20.         self.setGeometry(300, 300, 500, 500)
  21.     def send(self):
  22.         """
  23.         事件
  24.         :return:
  25.         """
  26.         def send_a():
  27.             while True:
  28.                 """
  29.                 逻辑代码
  30.                 """
  31.                 self.reviewEdit.setText("设置文案")
  32.         send_thread = threading.Thread(target=send_a)
  33.         # 启动线程
  34.         send_thread.start()
  35. if __name__ == '__main__':
  36.     app = QApplication(sys.argv)
  37.     ex = FileChooserApp()
  38.     ex.show()
  39.     sys.exit(app.exec_())
复制代码
View Code2)崩溃原因
上述中试图在子线程send_a方法中给文本编辑器设置文案。这是不允许的,因为 PyQt 和大多数 GUI 框架一样,要求所有的 GUI 更新必须在主线程(也称为 GUI 线程)中执行。
3)改进方法
既然在子线程中无法操作主线程gui更新,那么只能在主线程中去执行,这就需要信号与槽的配合了。我们先来自定义一个信号
  1. class YourThread(QObject):
  2.     show_warning_signal = pyqtSignal()
  3.     def run(self):
  4.         self.show_warning_signal.emit()
复制代码
在初始化的时候去实例化YourThread类,连线信号与槽
  1. class FileChooserApp(QMainWindow):
  2.     def __init__(self):
  3.         super().__init__()
  4.         self.initUI()
  5.         self.your = YourThread()
  6.         self.your.show_warning_signal.connect(self.settext)
复制代码
接着在子线程中直接去触发信号即可
  1.     def send(self):
  2.         def send_a():
  3.             while True:
  4.                 """
  5.                 循环体
  6.                 """
  7.                 self.your.run()
  8.                 time.sleep(2)
  9.         send_thread = threading.Thread(target=send_a)
  10.         # 启动线程
  11.         send_thread.start()
复制代码
执行每次循环需要等待2s,避免出现无限循环导致应用程序冻结、响应缓慢或其他线程相关的问题
三.实例
  1. import sysimport threadingimport timefrom PyQt5.QtCore import QObject, pyqtSignalfrom PyQt5.QtWidgets import QPushButton, QTextEdit, QApplication, QHBoxLayout, QWidgetclass YourThread(QObject):
  2.     show_warning_signal = pyqtSignal()
  3.     def run(self):
  4.         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_())
复制代码
 

来源:https://www.cnblogs.com/lihongtaoya/p/18197784
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具