Reputation: 4398
I have pyqt gui with some text display that is updated periodically via function updateTelemetry()
Here is how my code works. When the user clicks the button, the buttonHandler is called. And updateTelemetry is called iteratively every 10s.:
def buttonHandler(self):
self.monitor=true
self.updateTelemetry()
def updateTelemetry(self):
try:
#update values on gui
finally:
if self.monitor:
QtCore.QTimer.singleShot(10000, self.updateTelemetry)
This approach works, and lets me get an update around every 10s. However, every 10s, the entire gui freezes for a few seconds and then updates. Something that I'm doing seems to be blocking. I'm not sure how that is happening. I thought that qtimer.singleshot would create a separate thread?
Is there a better way to do what I'm doing?
Upvotes: 0
Views: 1351
Reputation: 11849
A QTimer
does not create a separate thread. QTimer
simply emits a signal in the main thread after a given timeout. As such, everything (including your device reading code) is still running in the main thread.
You should move the code that reads from your device to a QThread
and emit a signal from the QThread
to the main thread where you can update your GUI. GUI updates must only be done from the main thread. Only signal emission is thread safe!
The following is a rough implementation of a QThread
.
class MyThread(QObject):
send_data_to_gui = pyqtSignal(str)
def __init__(self,*args,**kwargs):
QObject.__init__(self,*args,**kwargs)
@pyqtSlot()
def run(self):
while True:
# get data from device
self.send_data_to_gui.emit(data_from_device)
time.sleep(10)
...
thread = QThread()
my_thread = MyThread()
my_thread.send_data_to_gui.connect(my_slot)
my_thread.moveToThread(thread)
thread.started.connect(my_thread.run)
thread.start()
Note that in it's current form, the QThread
actually has it's own event loop, so you can do all sorts of complicated things (however the while True
is blocking the event loop at the moment). As the thread has an independent event loop, you could replace the while True
with a QTimer
, configured to fire every 10 seconds (make sure the QTimer
is actually created in the thread though. MyThread.__init__
still runs in the main thread but the contents of MyThread.run
will be executed in the new thread). You also might want to add the ability to shutdown the thread, or add other functionality I don't know about!
If you have trouble with your implementation, feel free to post a follow-up question on stack overflow!
Upvotes: 1