Reputation: 673
I'm using PyQt4 and I've created a window with a toggle button. When I select the button, I would like to start a loop that updates the screen as quickly as possible. Currently, it locks up my windows and I cannot select the button again to turn off the loop or even move the window. I was hoping to find a way to do this without threads. I can't post my actual code, but this is basically what I have right now.
self.connect(self.pushButton,SIGNAL("toggled(bool)"),self.testLoop)
def testLoop(self, bool):
while bool:
print "looping"
Upvotes: 2
Views: 3746
Reputation: 2664
Use a separate thread for the looping.
import threading
self.connect(self.pushButton,SIGNAL("toggled(bool)"),self.on_testLoop)
def on_testLoop(self, bool):
threading.Thread(target=self.testLoop, args=(bool,)).start()
def testLoop(self, bool):
while bool:
print "looping"
Another method I found very useful was to make the function into a generator. This enables you to do stuff after each iteration.
self.connect(self.pushButton,SIGNAL("toggled(bool)"),self.on_testLoop)
def on_testLoop(self, bool):
for _ in testLoop(bool):
# do some stuff, update UI elements etc.
def testLoop(self, bool):
while bool:
print "looping"
yield
I don't know how good it is to use a generator for this, as I'm quite new to PyQt and gui programming, but this worked quite well for me.
Upvotes: 2
Reputation: 120678
The approach you take will be mostly determined by the nature of the task that your loop is carrying out.
If you can break the task down into very small steps, it may be possible to simply start your loop with a timer and then call processEvents
on every step to update your gui:
from PyQt4 import QtGui, QtCore
class Window(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.label = QtGui.QLabel('Count = 0', self)
self.button = QtGui.QPushButton('Start', self)
self.button.clicked.connect(self.handleButton)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.label)
layout.addWidget(self.button)
self._active = False
def handleButton(self):
if not self._active:
self._active = True
self.button.setText('Stop')
QtCore.QTimer.singleShot(0, self.runLoop)
else:
self._active = False
def closeEvent(self, event):
self._active = False
def runLoop(self):
from time import sleep
for index in range(100):
sleep(0.05)
self.label.setText('Count = %d' % index)
QtGui.qApp.processEvents()
if not self._active:
break
self.button.setText('Start')
self._active = False
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
Upvotes: 4