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

PySide6线程停止按钮失效问题求助及代码排查

问题分析与解决方案

你的停止按钮无法正常工作,核心问题有以下几点:

  1. 自定义stop变量的线程安全性无法保证,跨线程直接修改普通变量可能导致状态不同步
  2. time.sleep(10)是阻塞调用,这段时间线程无法检查停止信号,导致停止指令延迟生效
  3. 每次点击启动按钮都重复连接信号,会导致日志重复输出
  4. 未限制线程重复启动,多次点击启动按钮会触发错误

下面是修复后的代码及修改说明:

修复后的线程类代码

import time
from PySide6.QtCore import QThread, Signal
from selenium import webdriver

class Potok_Controller(QThread):
    mysignal = Signal(str)
    finish_signal = Signal()

    def __init__(self, parent=None):
        super(Potok_Controller, self).__init__(parent)
        self.urls = ['https://google.com/', 'https://youtube.com/']
        self.driver = None

    def run(self):
        # 初始化浏览器一次,避免重复启动占用资源
        try:
            self.driver = webdriver.Chrome(executable_path='chromedriver\\chromedriver.exe')
            while not self.isInterruptionRequested():
                for url in self.urls:
                    # 每次循环前检查是否收到停止请求
                    if self.isInterruptionRequested():
                        break
                    self.mysignal.emit(f'打开 {url}')
                    self.driver.get(url)
                    # 将10秒睡眠拆分为10次1秒,每次睡眠后检查停止请求
                    for _ in range(10):
                        if self.isInterruptionRequested():
                            break
                        QThread.msleep(1000)
                if self.isInterruptionRequested():
                    break
        except Exception as e:
            self.mysignal.emit(f'错误: {str(e)}')
        finally:
            # 确保浏览器被正确关闭
            if self.driver:
                self.driver.quit()
            self.finish_signal.emit()

    def stop_thread(self):
        # 使用Qt内置的中断请求机制,线程安全
        self.requestInterruption()
        self.wait()  # 等待线程安全退出

修复后的主窗口代码

import sys
from PySide6.QtWidgets import *
from Controller.Potok_Controller import Potok_Controller
from View.ui_potok import Ui_MainWindow

class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.myThread = Potok_Controller()
        
        # 只连接一次信号,避免重复输出日志
        self.myThread.mysignal.connect(self.update_log)
        self.myThread.finish_signal.connect(self.on_thread_finished)
        
        self.ui.pushButton.clicked.connect(self.start_thread)
        self.ui.pushButton_2.clicked.connect(self.stop_thread)
        
        # 初始化按钮状态
        self.ui.pushButton_2.setEnabled(False)

    def update_log(self, text):
        self.ui.plainTextEdit.appendPlainText(text)

    def start_thread(self):
        # 防止线程重复启动
        if not self.myThread.isRunning():
            self.ui.pushButton.setEnabled(False)
            self.ui.pushButton_2.setEnabled(True)
            self.myThread.start()

    def stop_thread(self):
        if self.myThread.isRunning():
            self.myThread.stop_thread()

    def on_thread_finished(self):
        # 线程结束后恢复按钮状态
        self.ui.pushButton.setEnabled(True)
        self.ui.pushButton_2.setEnabled(False)
        self.update_log('线程已停止')

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec())

关键修改点说明

  • 线程安全停止:使用Qt内置的requestInterruption()和isInterruptionRequested()替代自定义stop变量,保证跨线程状态同步的安全性
  • 响应及时:将10秒长睡眠拆分为多次短睡眠,每次睡眠后检查停止请求,让线程能快速响应停止指令
  • 资源优化:浏览器仅初始化一次,避免重复启动关闭带来的资源浪费和延迟
  • UI状态控制:添加按钮状态切换,防止重复启动线程,提升用户体验
  • 信号连接优化:仅连接一次信号,避免多次点击启动按钮导致日志重复输出

内容的提问来源于stack exchange,提问作者mr.VlaLin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 12:27:16