You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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操作:

  1. 将子域名枚举任务放到QThread子线程中执行,避免阻塞主线程。
  2. 加载条使用非模态显示(show()方法),不阻塞主线程。
  3. 通过信号槽机制,子线程完成任务后通知主线程关闭加载条并更新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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 04:57:23