在python中使用Qt实现取消按钮

在python中使用Qt实现取消按钮,python,qt,pyqt,Python,Qt,Pyqt,这个问题可能是愚蠢的,但给我一些背景:我收到了一堆GUI是用Qt编写的软件的代码,有人告诉我应该通过实现多线程来改进它,这样界面就不会冻结(我有一堆像我正在使用的模板那样编写的代码)。我一般不熟悉Qt或gui ATM我试图实现一个简单的取消按钮:由于后台的过程可能需要很长时间,我希望能够任意停止它(例如,因为其中一个输入值不正确或拼写错误)。 令人惊讶的是,我找不到很多关于这方面的详细问题或教程 也就是说,我尝试实现一个简单的小部件来了解它是如何工作的: import time import s

这个问题可能是愚蠢的,但给我一些背景:我收到了一堆GUI是用Qt编写的软件的代码,有人告诉我应该通过实现多线程来改进它,这样界面就不会冻结(我有一堆像我正在使用的模板那样编写的代码)。我一般不熟悉Qt或gui

ATM我试图实现一个简单的取消按钮:由于后台的过程可能需要很长时间,我希望能够任意停止它(例如,因为其中一个输入值不正确或拼写错误)。 令人惊讶的是,我找不到很多关于这方面的详细问题或教程

也就是说,我尝试实现一个简单的小部件来了解它是如何工作的:

import time
import sys
from PyQt5 import QtCore, QtGui, QtWidgets

class Calc(QtCore.QObject):
    new_val = QtCore.pyqtSignal(float)

    def __init__(self):
        super().__init__()
        self.a = 0

    def Stop(self, b=False):
        if b:
            QtCore.QThread.quit()   # This obviously doesn't work

    def upd(self, a):
        self.a = a
        a2 = a**2
        for i in range(10):  # To simulate a lengthy process
            time.sleep(1)

        self.new_val.emit(a2)

class CalcWidget(QtWidgets.QWidget):
   go_sig = QtCore.pyqtSignal(float)
   stop_sig = QtCore.pyqtSignal(bool)

    def __init__(self, arg):
        super().__init__()
        self.arg = arg
        self.arg_thread = QtCore.QThread()
        self.arg.moveToThread(self.arg_thread)

        self.stop = QtWidgets.QPushButton('Cancel')

        self.a = QtWidgets.QSpinBox()
        self.a2 = QtWidgets.QLabel('--')

        self.a.valueChanged.connect(self._go)
        self.go_sig.connect(self.arg.upd)

        self.stop.clicked.connect(self._Stop)
        self.stop_sig.connect(self.arg.Stop)

        self.arg.new_val.connect(self.myupd)
        
        # this is only the interface
        hbox = QtWidgets.QHBoxLayout()
        vbox1 = QtWidgets.QVBoxLayout()
        vbox1.setAlignment(QtCore.Qt.AlignLeft)
        vbox1.addWidget(self.a)

        hbox.addLayout(vbox1)

        vbox2 = QtWidgets.QVBoxLayout()
        vbox2.setAlignment(QtCore.Qt.AlignLeft)
        vbox2.addWidget(self.a2)
        vbox2.addWidget(self.stop)

        hbox.addLayout(vbox2)

        self.setLayout(hbox)

        self.arg_thread.start()

    def _go(self):
        self.go_sig.emit(self.a.value())

    def _Stop(self):
         self.stop_sig.emit(True)

    def myupd(self, a2):
        self.a2.setText(str(a2))



if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    calc = Calc()
    w = CalcWidget(calc)
    w.show()
    app.exec()
现在函数Stop()显然不起作用了,我尝试了不同的实现,比如从函数
CalcWidget.\u Stop()
中退出线程,或者在
Calc()
中定义一个变量,并在
Calc.upd
中的for循环中添加一个条件语句。 然而,在我看来,我错过了一些明显或简单的东西,我无法让它发挥作用。欢迎任何帮助或建议

编辑: 通过调整问题,我重新编写了
Stop
函数,如下所示:

def Stop():
    self.stop = True
其中,
self.stop
是一个类变量,现在我可以在循环中添加一个条件:

for i in range(10):
    if self.stop:
        break
    time.sleep(1)
但是,更改是排队的,因此线程完成循环,然后调用
Stop
。让这个没用。我想知道是否有办法解决这个问题。
我不想重新定义一个线程对象,因为在我看来,它需要更多的工作来重新实现已经编写和工作的代码的PAR。

< P>这是如何实现它的一个简短例子。 如果您想让我添加注释,请告诉我

from PyQt5 import QtWidgets, QtCore


class WorkerThread(QtCore.QThread):
    is_active = True
    
    def run(self):
        while self.is_active:
            print("Processing...")
            self.sleep(1)


class Window(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(Window, self).__init__(parent)
        
        self.start_button = QtWidgets.QPushButton("Start")
        self.cancel_button = QtWidgets.QPushButton("Cancel")
        
        self.start_button.clicked.connect(self.start)
        self.cancel_button.clicked.connect(self.stop)
        
        laytout = QtWidgets.QVBoxLayout()
        laytout.addWidget(self.start_button)
        laytout.addWidget(self.cancel_button)
        self.setLayout(laytout)
        
        self.worker = WorkerThread()
    
    def start(self):
        self.worker.is_active = True
        self.worker.start()
        
    def stop(self):
        self.worker.is_active = False

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    win = Window()
    win.show()
    sys.exit(app.exec_())

没有安全的方法可以任意“杀死”线程。如果要停止线程,必须为线程提供中断其计算并自行返回的机制,例如,通过在每次循环迭代中检查共享变量。问题是,如果我在循环中添加一个标志并从外部修改它,然后修改被排队等待循环完成为什么修改会被排队?我不想听起来很讽刺,因为我不是:如果我知道,我就不会有问题。有关更多信息,请参见我的编辑。因此,如果我理解正确,您已经在QThread对象周围添加了一个包装器,作为添加条件的一种方式