I have been strugling with this for some time. I will try to explain what i want to do , maybe you guys could help me.
So lets say I have GUI with status label on it and Two loops that look like this:
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()
I want a label (STATUS) to be updated with a results after START being pressed (done), and i want to cancel loops when STOP button is being pressed.
How to achieve this using Threads, QEventloop or any other way (if exists). I am pretty much beginner with PyQT so if someone have any idea - please share.
Thanks.
The easiest way to achieve this is by using generators, and an "idle timer".
The idea is to turn your loop into a generator using the yield
keyword, so that you can trigger each iteration from outside using next()
. Then you use Qt's low-level timer (startTimer()
, killTimer()
, and timerEvent()
) to create a timer with interval zero, that is called every time there are no more events to process, to run the next loop iteration. This gives you the opportunity to react to GUI events during your loop, e.g., to handle the stop button clicked()
signal.
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