PyQt6 GUI主线程冻结求助:子线程执行任务时界面卡顿
PyQt6主窗口卡顿冻结的问题解决
核心问题定位
你的主窗口冻结是因为子线程的启动方式完全错误,导致繁重任务直接在主线程执行,阻塞了GUI事件循环。错误集中在saveDatabase函数和线程的使用逻辑上。
具体错误点说明
错误调用run()方法:
self.thread.started.connect(self.thread.run())这行代码直接在主线程中执行了run(),而不是将其作为线程的执行函数。QThread.start()会自动调用run()方法,不需要手动连接started信号到run()。冗余且错误的moveToThread操作:
self.thread.moveToThread(self.thread)完全没有意义,QThread实例本身就是线程控制器,不需要将它移动到自己的线程中,这属于错误操作。进度条最大值计算错误:
numLinks = self.links.__sizeof__()返回的是列表对象的内存占用大小,不是列表中的元素数量,应该用len(self.links)来获取实际链接数量,否则进度条的范围会完全错误。线程未发射finished信号:
TaskThread的run()方法结束后没有发射finished信号,导致线程结束时无法触发清理逻辑。
修正后的代码
1. 修正saveDatabase函数
def saveDatabase(self): # 正确获取链接数量 numLinks = len(self.links) print(numLinks) self.progressBar.setRange(0, numLinks) self.thread = TaskThread(copy.deepcopy(self.links), copy.deepcopy(self.filePathLabel.text())) # 移除错误的moveToThread调用 # self.thread.moveToThread(self.thread) # 移除错误的started连接,start()会自动调用run() # self.thread.started.connect(self.thread.run()) self.thread.progress.connect(self.progressBarUp) self.thread.finished.connect(self.thread.quit) self.thread.finished.connect(self.thread.deleteLater) self.thread.start()
2. 修正TaskThread类
import os class TaskThread(QtCore.QThread): finished = pyqtSignal() progress = pyqtSignal(int) def __init__(self, links, filePath): QtCore.QThread.__init__(self, parent=None) self.links = links self.filePath = filePath def run(self): # 使用os.path.join拼接路径,避免跨平台问题 directoryPath = self.filePath summaryPath = os.path.join(directoryPath, "summary") imagesPath = os.path.join(directoryPath, "images") fullPagePath = os.path.join(directoryPath, "fullPage") # 批量创建目录,加入exist_ok=True避免重复创建报错 os.makedirs(summaryPath, exist_ok=True) os.makedirs(imagesPath, exist_ok=True) os.makedirs(fullPagePath, exist_ok=True) num = 0 for i in self.links: try: page = wikipedia.page(i) summary = page.summary images = page.images fullPage = page.content tempSummaryPath = os.path.join(summaryPath, i) tempImagesPath = os.path.join(imagesPath, i) tempFullPagePath = os.path.join(fullPagePath, i) # 写入摘要,指定utf-8编码避免特殊字符报错 with open(tempSummaryPath, 'w', encoding='utf-8') as f: f.write(summary) # 可补充写入完整页面内容的逻辑,原代码未处理 # with open(tempFullPagePath, 'w', encoding='utf-8') as f: # f.write(fullPage) num += 1 self.progress.emit(num) except Exception as e: # 捕获异常避免线程崩溃,可添加日志输出 print(f"处理链接{i}时出错: {str(e)}") num += 1 self.progress.emit(num) # 线程结束时发射finished信号 self.finished.emit()
额外优化建议
- 禁用按钮防止重复点击:在启动线程时禁用
saveFilesButton,线程结束后再启用,避免重复创建线程:def saveDatabase(self): self.saveFilesButton.setEnabled(False) # ...其他代码... self.thread.finished.connect(lambda: self.saveFilesButton.setEnabled(True)) - 处理网络请求超时:维基百科请求可能超时,可给
wikipedia.page()添加超时参数或重试逻辑。 - 进度条更新频率优化:如果链接数量极大,可每处理N个链接再发射一次进度信号,减少GUI刷新压力。
内容的提问来源于stack exchange,提问作者Evan Lazzaro
相关产品推荐
相关产品推荐

