1

我已经为此苦苦挣扎了一段时间。我会尝试解释我想做什么,也许你们可以帮助我。

所以假设我有带有状态标签的 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()               

我希望在按下 START(完成)后使用结果更新标签(STATUS),并且我想在按下 STOP 按钮时取消循环。

如何使用线程、QEventloop 或任何其他方式(如果存在)来实现这一点。我几乎是 PyQT 的初学者,所以如果有人有任何想法 - 请分享。

谢谢。

4

3 回答 3

2

实现这一点的最简单方法是使用生成器和“空闲计时器”。

这个想法是使用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
于 2011-08-29T06:33:58.600 回答
2

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()
于 2011-09-09T10:57:33.220 回答
-1

我想给出我对这个问题的解决方案。

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

我发现使用 QTimer 对我来说是唯一可行的解​​决方案,尝试了 yield 一个并且对 self.stop 的检查是 True

由于该线程非常过时,我将使用另一个与此处发布的非常相似的示例。

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

我们将使用该对象,在定时器发出信号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

这行得通,至少对我来说!希望这对某人有所帮助!

于 2015-10-26T18:31:27.347 回答