PySide6 GUI加载条无限循环,任务无法执行求助
PySide6加载条无限运行问题解决
问题描述
在PySide6 GUI程序中添加加载条后,加载条无限循环无法关闭,但不使用加载条时,子域名枚举任务仅需10-20秒即可完成。
原加载条类代码:
class LoadingDialog(QDialog): def __init__(self): super().__init__() self.setWindowTitle("Working on your task") self.setWindowFlags(Qt.Dialog | Qt.CustomizeWindowHint | Qt.WindowTitleHint) self.setFixedSize(300, 100) # Fixed size dialog self.progress = QProgressBar(self) self.progress.setGeometry(30, 40, 240, 30) self.progress.setRange(0, 0) # Indeterminate progress bar self.label = QLabel("Enumerating Please Wait...", self) self.label.setGeometry(110, 10, 80, 20) self.setLayout(QVBoxLayout()) self.layout().addWidget(self.label) self.layout().addWidget(self.progress) def showEvent(self, event): super().showEvent(event) self.progress.setRange(0, 0) # Start indeterminate progress def closeEvent(self, event): super().closeEvent(event) self.progress.setRange(0, 0) # Reset progress on close
原主GUI调用代码:
self.loading_dialog.exec() self.output_text.clear() self.output_text.append(f"Enumerating subdomains for {domain} using wordlist...\n") subdomains = self.subdomain_enum(domain, wordlist) if subdomains: self.display_subdomains("Wordlist", subdomains) else: self.output_text.append("No subdomains found.") self.loading_dialog.close()
原因分析
核心问题是**exec()方法会阻塞主线程**:
exec()是模态对话框的显示方法,调用后会一直阻塞主线程,直到对话框被关闭。- 原代码中,
exec()之后的任务代码(子域名枚举)根本无法执行,导致加载条永远不会被调用close(),陷入无限循环。
同时,子域名枚举中的DNS查询是耗时操作,如果在主线程执行会阻塞UI更新,即使不用模态对话框也会导致加载条动画卡顿。
解决方案
使用多线程分离耗时任务与主线程UI操作:
- 将子域名枚举任务放到
QThread子线程中执行,避免阻塞主线程。 - 加载条使用非模态显示(
show()方法),不阻塞主线程。 - 通过信号槽机制,子线程完成任务后通知主线程关闭加载条并更新UI。
修改后的完整代码示例
1. 子线程类(处理耗时任务)
from PySide6.QtCore import QThread, Signal import dns.resolver class SubdomainEnumThread(QThread): finished = Signal(list) # 任务完成时发送结果列表 error = Signal(str) # 任务出错时发送错误信息 def __init__(self, domain, wordlist): super().__init__() self.domain = domain self.wordlist = wordlist def run(self): output = [] try: with open(self.wordlist, 'r') as file: subdomains = file.read().splitlines() for subdomain in subdomains: try: full_domain = f"{subdomain}.{self.domain}" result = dns.resolver.resolve(full_domain, 'A') for ipval in result: output_line = f'{full_domain} | {ipval.to_text()}' output.append(output_line) except Exception: pass self.finished.emit(output) except Exception as e: self.error.emit(str(e))
2. 简化后的加载条类
from PySide6.QtWidgets import QDialog, QProgressBar, QLabel, QVBoxLayout from PySide6.QtCore import Qt class LoadingDialog(QDialog): def __init__(self): super().__init__() self.setWindowTitle("Working on your task") self.setWindowFlags(Qt.Dialog | Qt.CustomizeWindowHint | Qt.WindowTitleHint) self.setFixedSize(300, 100) self.progress = QProgressBar() self.progress.setRange(0, 0) # 不确定进度条 self.label = QLabel("Enumerating Please Wait...") layout = QVBoxLayout() layout.addWidget(self.label) layout.addWidget(self.progress) self.setLayout(layout)
3. 主GUI中的调用逻辑
# 假设这是主窗口类的方法 def start_enumeration(self, domain, wordlist): # 初始化并显示非模态加载条 self.loading_dialog = LoadingDialog() self.loading_dialog.show() # 初始化并启动子线程 self.enum_thread = SubdomainEnumThread(domain, wordlist) self.enum_thread.finished.connect(self.handle_enum_finish) self.enum_thread.error.connect(self.handle_enum_error) self.enum_thread.start() def handle_enum_finish(self, subdomains): # 关闭加载条 self.loading_dialog.close() # 更新UI显示结果 self.output_text.clear() self.output_text.append(f"Enumerating subdomains for {domain} using wordlist...\n") if subdomains: self.display_subdomains("Wordlist", subdomains) else: self.output_text.append("No subdomains found.") def handle_enum_error(self, error_msg): self.loading_dialog.close() self.output_text.append(f"Error occurred: {error_msg}") # 原有的display_subdomains方法保持不变 def display_subdomains(self, source, subdomains): self.output_text.append(f"From {source}:") if subdomains: for subdomain in subdomains: self.output_text.append(f" - {subdomain}") else: self.output_text.append(f" No subdomains found from {source}.")
关键说明
- 使用
QThread将DNS查询等耗时操作移到子线程,主线程专注于UI更新,避免加载条卡顿或无限运行。 - 加载条用
show()而非exec(),非模态对话框不会阻塞主线程,保证UI事件正常处理。 - 信号槽机制确保子线程任务完成后,主线程安全地更新UI和关闭加载条,符合PySide6的线程安全规范。
内容的提问来源于stack exchange,提问作者Levi
相关产品推荐
相关产品推荐

