问题描述:

I'm trying to create a simple threaded application whereby i have a method which does some long processing and a widget that displays a loading bar and cancel button.

My problem is that no matter how i implement the threading it doesn't actually thread - the UI is locked up once the thread kicks in. I've read every tutorial and post about this and i'm now resorting on asking the community to try and solve my problem as i'm at a loss!

Initially i tried subclassing QThread until the internet said this was wrong. I then attempted the moveToThread approach but it made zero difference.

Initialization code:

loadingThreadObject = LoadThread(arg1)

loadingThread = PythonThread()

loadingThreadObject.moveToThread(loadingThread)

loadingThread.started.connect(loadingThreadObject.load)

loadingThread.start()

PythonThread class (apparently QThreads are bugged in pyQt and don't start unless you do this):

class PythonThread (QtCore.QThread):

def __init__(self, parent=None):

QtCore.QThread.__init__(self, parent)

def start(self):

QtCore.QThread.start(self)

def run(self):

QtCore.QThread.run(self)

LoadThread class:

class LoadThread (QtCore.QObject):

results = QtCore.Signal(tuple)

def __init__ (self, arg):

# Init QObject

super(QtCore.QObject, self).__init__()

# Store the argument

self.arg = arg

def load (self):

#

# Some heavy lifting is done

#

loaded = True

errors = []

# Emits the results

self.results.emit((loaded, errors))

Any help is greatly appreciated!

Thanks.

Ben.

网友答案:

The problem was with the SQL library I was using (a custom in-house solution) which turned out not to be thread safe and thus performed blocking queries.

If you are having a similar problem, first try removing the SQL calls and seeing if it still blocks. If that solves the blocking issue, try reintroducing your queries using raw SQL via MySQLdb (or the equivalent for the type of DB you're using). This will diagnose whether or not the problem is with your choice of SQL library.

网友答案:

The function connected to the started signal will run the thread which it was connected, the main GUI thread. However, a QThread's start() function executes its run() method in the thread after the thread is initialized so a subclass of QThread should be created and its run method should run LoadThread.load, the function you want to execute. Don't inherit from PythonThread, there's no need for that. The QThread subclass's start() method should be used to start the thread.

PS: Since in this case the subclass of QThread's run() method only calls LoadThread.load(), the run() method could be simply set to LoadThread.load:

class MyThread(QtCore.QThread):
    run = LoadThread.load # x = y in the class block sets the class's x variable to y

An example:

import time
from PyQt4 import QtCore, QtGui
import sys
application = QtGui.QApplication(sys.argv)

class LoadThread (QtCore.QObject):
    results = QtCore.pyqtSignal(tuple)

    def __init__ (self, arg):
         # Init QObject
         super(QtCore.QObject, self).__init__()

         # Store the argument
         self.arg = arg

    def load(self):
         #
         # Some heavy lifting is done
         #
         time.sleep(5)
         loaded = True
         errors = []

         # Emits the results
         self.results.emit((loaded, errors))

l = LoadThread("test")

class MyThread(QtCore.QThread):
    run = l.load

thread = MyThread()

button = QtGui.QPushButton("Do 5 virtual push-ups")
button.clicked.connect(thread.start)
button.show()
l.results.connect(lambda:button.setText("Phew! Push ups done"))
application.exec_()
相关阅读:
Top