Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/291.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python PYQT-如何使用cancel按钮取消GUI中的循环?_Python_Multithreading_Pyqt_Qeventloop - Fatal编程技术网

Python PYQT-如何使用cancel按钮取消GUI中的循环?

Python PYQT-如何使用cancel按钮取消GUI中的循环?,python,multithreading,pyqt,qeventloop,Python,Multithreading,Pyqt,Qeventloop,我已经为此绞尽脑汁一段时间了。我会尽力解释我想做什么,也许你们能帮我 假设我有一个带有状态标签的GUI 两个循环如下所示: for _a in range(3000): self.changeLabel('_a= '+ str(_a)) for _b in range(5000): self.changeLabel('_b=' + str(_b)) def changeLabel(self,_text): self.ui.STATUS.setText(_text

我已经为此绞尽脑汁一段时间了。我会尽力解释我想做什么,也许你们能帮我

假设我有一个带有状态标签的GUI 两个循环如下所示:

for _a in range(3000):
     self.changeLabel('_a= '+ str(_a))

for _b in range(5000):
     self.changeLabel('_b=' + str(_b))

def changeLabel(self,_text):
     self.ui.STATUS.setText(_text)   <---ui is a GUI where label is placed. 
     APP.processEvents()               
适用于范围(3000)内的_a:
self.changeLabel(''u a='+str('u a))
对于范围(5000)内的_b:
self.changeLabel(''u b='+str('u b))
def changeLabel(自身,_文本):

self.ui.STATUS.setText(_text)实现这一点的最简单方法是使用生成器和“空闲计时器”

我们的想法是使用
yield
关键字将循环转换为生成器,这样您就可以使用
next()
从外部触发每次迭代。然后使用Qt的低级计时器(
startTimer()
killTimer()
,和
timerEvent()
)创建一个间隔为零的计时器,每当没有更多事件要处理时调用该计时器,以运行下一个循环迭代。这使您有机会在循环过程中对GUI事件做出反应,例如,处理停止按钮
clicked()
信号

class MyWidget(QWidget):  # Or whatever kind of widget you are creating

    def __init__(self, parent, **kwargs):
        super(MyWidget, self).__init__(parent, **kwargs)
        # ... Create your widgets, connect signals and slots, etc.
        self._generator = None
        self._timerId = None

    def loopGenerator(self):
        # Put the code of your loop here
        for a in range(3000):
            self.ui.STATUS.setText("a=" + a)
            # No processEvents() needed, just "pause" the loop using yield
            yield

    def start(self):  # Connect to Start-button clicked()
        self.stop()  # Stop any existing timer
        self._generator = self.loopGenerator()  # Start the loop
        self._timerId = self.startTimer(0)   # This is the idle timer

    def stop(self):  # Connect to Stop-button clicked()
        if self._timerId is not None:
            self.killTimer(self._timerId)
        self._generator = None
        self._timerId = None

    def timerEvent(self, event):
        # This is called every time the GUI is idle.
        if self._generator is None:
            return
        try:
            next(self._generator)  # Run the next iteration
        except StopIteration:
            self.stop()  # Iteration has finshed, kill the timer

Ferdinand的答案很好,因为它避免了使用processEvents()来创建自己的事件循环。然而,我认为有一个更简单的解决方案:为什么不在按下停止按钮时设置一个标志,并在设置标志后退出循环?比如:

def stopClicked(self):
    self.stop = True

for _a in range(3000):
    self.changeLabel('_a= '+ str(_a))    
    if self.stop:
        self.stop = False
        break

def changeLabel(self,_text):
    self.ui.STATUS.setText(_text)   <---ui is a GUI where label is placed. 
    APP.processEvents()
def stopplicked(自):
self.stop=True
对于范围(3000)内的_a:
self.changeLabel(''u a='+str('u a))
如果自动停止:
self.stop=False
打破
def changeLabel(自身,_文本):

self.ui.STATUS.setText(_text)我想给出这个问题的解决方案

在使用PyQt创建用于从传感器拍摄实时照片的循环时,我遇到了类似的问题

我发现使用QTimer是我唯一可行的解决方案,我已经尝试了yield解决方案,并且检查self.stop是正确的

因为这个线程已经过时了,我将使用另一个例子,这个例子与这里发布的非常相似

我们想用某种信号(在本例中是击键)初始化计数器,然后用另一次击键停止它

我们将使用
QTimer
对象,在计时器发出的
timeout()
信号期间升级计数器

class MyExample(QObject):

    timer = QTimer()
    cont = 0

    def __init__(self):

        super(QObject, self).__init__()

        # !!! IMPORTANT PART !!!
        # Here we connect the timeout of the timer to the count
        # function!
        self.timer.timeout.connect(self.cont)

    def keyEvent(self, e):

        # Here we connect the keystroke to the event 
        # on the object!
        if e.key() == Qt.Key_B:

            self.start()

        elif e.key() == Qt.Key_S:

            self.stop()

    def start(self):
        # Number of milliseconds the timer waits until the timeout
        self.timer.start(1000)

    def stop(self):
        self.timer.stop()

    def count(self):
        # Increase the counter on timeout
        self.cont = self.cont + 1
        print self.cont
这起作用了,至少对我来说是这样!
希望这对别人有帮助

一,。使用间隔为0的QTimer不是比使用低级QObject计时器功能更容易吗?2.这将是一个小处理大量的事件。也许每个事件做10到100次迭代而不是一次?@Macke:我想你也可以使用QTimer。不过,我不认为这会让事情变得更容易。是的,您可以在
生成
ing之前进行多次迭代,但是您必须调用
processEvents()
来更新其间的GUI。通过只使用一次迭代,您不必担心这一点。请注意,这只是一个“概念证明”,OP的任务是根据他/她的需要调整它。那么线程呢?是否可以在线程上执行此操作,因为PYQT应该有自己的线程。@泽波夫:当然可以使用线程。但是:Python中没有“真正的”线程,因为全局解释器锁(有关更多信息,请查看该术语)。此外,设置线程和同步通信以检查工作线程是否应该停止要比此解决方案付出更多的努力。据我所知,PYQT有自己的独立于平台的线程,在python 3中,线程是不同的-更好,而且没有GIL。我只是想举一个例子来说明如何使用线程来实现这一点。如果有人愿意的话:)谢谢!这并没有解决发布的线程问题。QTimer可能是您唯一的解决方案,但这并不意味着它是OP的解决方案。这应该是一个评论。对不起,我认为它是解决问题的替代方案,因为它是我唯一有效的解决方案。