问题
每次运行到耗时方法时界面就卡死,无响应,花费了很长事件才把问题解决了,记录一下
原因分析
程序在主线程中执行,当主程序中有一个事件比较耗时时,主程序就会等耗时事件处理完才会进行下一步,此时界面就会卡死出现无响应的状态
解决办法
- 使用多线程
主线程只执行界面显示
子线程中执行耗时任务
简单Qthread实现
当使用PyQt编写GUI应用程序时,可以使用QThread类来执行耗时的任务,以避免主线程阻塞和页面无响应的问题。下面是一个简单的完整可运行代码示例,演示了如何在PyQt中使用QThread。
import sys
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QPushButton
# 自定义的工作线程类
class WorkerThread(QThread):
# 定义一个信号,用于在工作完成后发送通知
# 没什么变量可以传输的,就置为空就可以了
finished = pyqtSignal()
def run(self):
# 执行耗时的任务
self.do_work()
# 发送工作完成的信号
self.finished.emit()
def do_work(self):
# 模拟耗时的任务
import time
time.sleep(5)
# 主窗口类
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("QThread示例")
self.setGeometry(100, 100, 300, 200)
self.label = QLabel("等待工作完成...", self)
self.label.setGeometry(50, 50, 200, 30)
self.start_button = QPushButton("开始", self)
self.start_button.setGeometry(100, 100, 100, 30)
self.start_button.clicked.connect(self.start_work)
self.worker_thread = WorkerThread()
self.worker_thread.finished.connect(self.on_worker_finished)
def start_work(self):
# 启动工作线程
self.worker_thread.start()
def on_worker_finished(self):
# 工作完成后更新标签文字
self.label.setText("工作完成!")
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
在这个示例中,我们创建了一个自定义的工作线程类WorkerThread
,继承自QThread
。在WorkerThread
中,我们重写了run
方法,该方法会在线程启动时自动调用。在run
方法中,我们执行了一个模拟的耗时任务do_work
,在任务完成后发送了一个自定义的信号finished
。
在主窗口类MainWindow
中,我们创建了一个QLabel
控件用于显示文字。在窗口初始化时,我们创建了一个WorkerThread
实例,并将其finished
信号连接到槽函数on_worker_finished
。然后,我们调用start_work
方法启动工作线程。
当工作线程完成任务时,会发出finished
信号,触发槽函数on_worker_finished
。在槽函数中,我们更新了标签控件的文字,将其设置为"工作完成!"。(只有在工作线程发射finished
信号后,槽函数self.on_worker_finished
才会被调用。)
通过使用QThread
,耗时的任务在工作线程中执行,不会阻塞主线程,从而避免了页面无响应的问题。同时,通过使用信号和槽机制,我们可以在工作完成后更新UI控件的状态。
总结思路:
通过点击按钮触发启动工作线程,线程的run()方法完成耗时任务,完成后发送完成信号后便可触发控件显示文字。