#!/usr/bin/env python from PyQt4 import QtGui,QtCore import sys from collections import deque class MainWindow(QtGui.QMainWindow): def __init__(self,fname=None): """ only to show an example of my worker thread """ QtGui.QMainWindow.__init__(self) self.proc = None self.setCentralWidget(QtGui.QTextEdit()) self.toolbar = self.addToolBar('MyTools') self.primes = QtGui.QAction('Primes', self) self.connect(self.primes, QtCore.SIGNAL('triggered()'),self.twentyPrimes) self.toolbar.addAction(self.primes) self.stop = QtGui.QAction('Stop', self) self.connect(self.stop, QtCore.SIGNAL('triggered()'),self.stopPrimes) self.toolbar.addAction(self.stop) self.prime_list = [2,3] self.prime_index = 4 def Primer(self): """ Gets the next prime number, disclaimer: I don't know if this works, I just know it takes a long time """ check = True add = True while check==True: add = True for item in self.prime_list: data = self.prime_index%item if data==0: self.prime_index += 1 add = False break if add==True: self.prime_list.append(self.prime_index) check = False def twentyPrimes(self): """This is 20,000 prime numbers, I want to demonstrate, that by using this worker and a queue you can interrupt the process early""" self.primes.setEnabled(False) action_args_kwargs = [(self.Primer,[],{})]*20000 self.proc = MultiWorker(self,self.enableToolbar,action_args_kwargs) self.connect(self.proc,QtCore.SIGNAL("cleanUp()"),self.updateText) self.proc.start() def stopPrimes(self): if self.proc: self.proc.endProcess() self.proc = None def enableToolbar(self): self.proc = None self.primes.setEnabled(True) def updateText(self): self.centralWidget().setText("%s"%self.prime_list) class Worker(QtCore.QThread): """ The idea of this thread is to run a time consuming process without shutting down your gui. Whatever starts this process needs to clean it up by emitting a "cleanUp()" signal is prefered. """ def __init__(self,parent,action,callback,args=[],kwargs={}): QtCore.QThread.__init__(self,parent) parent.connect(self,QtCore.SIGNAL("finished()"),callback) self.action = action self.args = args self.kwargs = kwargs self.data = None def run(self): try: self.data = self.action(*self.args,**self.kwargs) finally: self.connect(self.parent(),QtCore.SIGNAL("cleanUp()"),QtCore.SLOT("deleteLater()")) def cleanUp(self): self.deleteLater() def get(self): return self.data class MultiWorker(QtCore.QThread): """ This is a utility class for executing many commands in succession. action_args must be a will composed list of (function,args,kwargs) tuples Note that it will take care of its own clean up. """ def __init__(self,parent,callback,action_args_kwargs): QtCore.QThread.__init__(self) if callback: parent.connect(self,QtCore.SIGNAL("finished()"),callback) self.connect(self,QtCore.SIGNAL("started()"),self.nextStep) self.action_args = deque(action_args_kwargs) def run(self): self.exec_() self.deleteLater() def nextStep(self): self.emit(QtCore.SIGNAL("cleanUp()")) self.doLoop() if self.action_args: action,args,kwargs = self.action_args.pop() proc = Worker(self,action,self.nextStep,args,kwargs) proc.start() else: self.quit() def doLoop(self): """ This is abstract,to do some intermediate action, possibly emit a signal """ pass def endProcess(self): """ end the chain of command as soon as the last event has finished """ self.action_args = None if __name__=='__main__': app = QtGui.QApplication(sys.argv) mw = MainWindow() mw.show() sys.exit(app.exec_())