Reputation: 899
I want my Python backend to not have to wait for my PyQt GUI to draw (lots of) stuff. Is there a better/correct way of doing this in PyQt than like in the code example below? Is it necessary to use the threading import or does PyQt have its own better way of doing it?
import time
from threading import Thread
class Backend(Thread):
def __init__(self):
super().__init__()
def run(self):
for i in range(20):
print("Backend heavy work")
time.sleep(4)
class GUI(Thread):
def __init__(self):
super().__init__()
def run(self):
for i in range(20):
print("GUI drawing stuff")
time.sleep(0.5)
if __name__ == '__main__':
thread_backend = Backend()
thread_gui = GUI()
thread_backend.start()
thread_gui.start()
I tried doing it with Qtimer but didn’t get it to work. Thank you!
Upvotes: 0
Views: 1853
Reputation: 847
You cannot update the UI from outside the Qt loop. What you can do is use qt signals to connect to methods to do the job for you. As an example
class GUI(QtCore.QObject): # must be a class that inherits QObject to use signals, I believe
drawSignal = QtCore.pyqtSignal(int)
def __init__(self):
super().__init__()
self.drawSignal.connect(self._drawStuff) # The underscore thing is a little hacky, but sort of pythonic I think, and makes the API clean.
self.drawStuff = self.drawSignal.emit
def _drawStuff(self, i):
# do whatever you want to the gui here
pass
class GUILoop(Thread):
def __init__(self, gui):
super().__init__()
self.gui = gui
def run(self):
for i in range(20):
self.gui.drawStuff(i)
time.sleep(0.5)
if __name__ == '__main__':
gui = GUI()
thread_backend = Backend()
thread_gui = GUILoop(gui)
thread_backend.start()
thread_gui.start()
It may seem a little weird, but it fits the strengths of both Qt and Python well. It probably also makes sense to just add the signals to your QMainWindow
class, which already is a QObject
.
Upvotes: 1