I tried to make my PyQt4 program more responsive by moving some blocking code to a seperate QThread. As it didn't work, I created this minimal example as a demonstration:
import sys
import time
from PyQt4 import QtCore, QtGui
class Sleeper(QtCore.QObject):
def __init__(self):
super(Sleeper, self).__init__()
self.timer = QtCore.QTimer()
self.timer.timeout.connect(self.sleep)
self.timer.start(1000)
def sleep(self):
time.sleep(1)
class MyGUI(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MyGUI, self).__init__(parent)
self.button = QtGui.QPushButton("hello", self)
self.sleeper = Sleeper()
self.thread = QtCore.QThread()
self.sleeper.moveToThread(self.thread)
self.thread.start()
if __name__ == "__main__":
qapp = QtGui.QApplication(sys.argv)
my_gui = MyGUI()
my_gui.show()
qapp.exec_()
The problem with this code is that the sleep-command still blocks the user interface. I found that it works as expected when I create, connect and run the QTimer outside the Sleeper class, but I do not understand why.
The connect
is called while the object was in the GUI thread so the event handler will also be executed in the GUI thread. Try moving to thread first, then creating the connection.
class Sleeper(QtCore.QObject):
def __init__(self):
super(Sleeper, self).__init__()
self.timer = QtCore.QTimer()
def initialize(self): # Creating the connection and starting separately
self.timer.timeout.connect(self.sleep)
self.timer.start(1000)
def sleep(self):
time.sleep(1)
class MyGUI(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MyGUI, self).__init__(parent)
self.button = QtGui.QPushButton("hello", self)
self.sleeper = Sleeper()
self.thread = QtCore.QThread()
self.sleeper.moveToThread(self.thread) # Move to thread
self.sleeper.initialize() # Create connection now
self.thread.start()
Also, check this: Qt connection type between threads: why does this work?