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