PyQt5如何点击一个按钮终止另一个按钮触发的运行事件
解决方案
你的代码无法实现中止功能的核心原因是:counter函数直接运行在Qt主线程(UI线程)中,time.sleep(0.1)会完全阻塞主线程的事件循环,导致Abort按钮的点击事件根本无法被响应,自然不可能触发中止逻辑。
你需要将耗时的计数逻辑放到独立的子线程中运行,通过Qt原生的线程中断机制实现安全终止,修改方案如下:
完整修改后代码
from PyQt5 import QtCore, QtGui, QtWidgets import time # 新增工作线程类,处理计数逻辑 class CountWorker(QtCore.QThread): def run(self): for i in range(1000): # 判断是否收到中断请求,收到就退出循环 if self.isInterruptionRequested(): print("计数已中止") break print(i) # 用QThread自带的毫秒休眠代替time.sleep,避免阻塞事件 self.msleep(100) class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(800, 600) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.button = QtWidgets.QPushButton(self.centralwidget) self.button.setGeometry(QtCore.QRect(200, 210, 91, 81)) self.button.setObjectName("button") self.sweepbutton = QtWidgets.QPushButton(self.centralwidget) self.sweepbutton.setGeometry(QtCore.QRect(460, 210, 93, 81)) self.sweepbutton.setObjectName("sweepbutton") MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 26)) self.menubar.setObjectName("menubar") MainWindow.setMenuBar(self.menubar) self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) # 初始化工作线程 self.count_thread = CountWorker() # 绑定Abort按钮的点击事件到中止函数 self.button.clicked.connect(self.interupt_counter) self.sweepbutton.clicked.connect(self.counter) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) self.button.setText(_translate("MainWindow", "Abort")) self.sweepbutton.setText(_translate("MainWindow", "Counter")) def counter(self): # 避免重复启动线程 if not self.count_thread.isRunning(): self.count_thread.start() def interupt_counter(self): # 线程运行中才触发中止 if self.count_thread.isRunning(): # 发送中断请求 self.count_thread.requestInterruption() # 等待线程安全退出 self.count_thread.wait() if __name__ == "__main__": import sys app = QtWidgets.QApplication(sys.argv) MainWindow = QtWidgets.QMainWindow() ui = Ui_MainWindow() ui.setupUi(MainWindow) MainWindow.show() sys.exit(app.exec_())
核心修改说明
- 新增了
CountWorker子线程类继承QThread,将计数逻辑放到run方法中执行,不会阻塞主线程的UI响应 - 用
isInterruptionRequested()判断是否收到中止信号,收到就主动退出循环,是线程安全的终止方式,不会出现资源泄漏 - 用
QThread.msleep()代替time.sleep(),更适配Qt的线程机制 - Abort按钮点击时调用
requestInterruption()发送中止信号,等待线程安全退出 - 增加了线程运行状态判断,避免重复启动线程或者对未运行的线程执行中止操作
注意:如果后续需要在计数过程中更新UI控件内容,不要直接在子线程的
run方法里操作UI,要通过自定义信号槽的方式将数据传递到主线程再更新。
内容的提问来源于stack exchange,提问作者andyon98
相关产品推荐
相关产品推荐

