6

Is there any way we can pass a parameter to QThread when the thread is started (.start) ?

I found an example of using pyqt thread in stackoverflow, but I was wondering how to pass a parameter, in case I want the worker thread to process a data that I pass to its run() function.

The post I refer to: Busy indication with PyQt progress bar

The code:

class MyCustomWidget(QtGui.QWidget):

    def __init__(self, parent=None):
        super(MyCustomWidget, self).__init__(parent)
        layout = QtGui.QVBoxLayout(self)       

        self.progressBar = QtGui.QProgressBar(self)
        self.progressBar.setRange(0,100)
        button = QtGui.QPushButton("Start", self)
        layout.addWidget(self.progressBar)
        layout.addWidget(button)

        button.clicked.connect(self.onStart)

        self.myLongTask = TaskThread()
        self.myLongTask.notifyProgress.connect(self.onProgress)


    def onStart(self):
        self.myLongTask.start()

    def onProgress(self, i):
        self.progressBar.setValue(i)


class TaskThread(QtCore.QThread):
    notifyProgress = QtCore.pyqtSignal(int)
    def run(self):
        for i in range(101):
            self.notifyProgress.emit(i)
            time.sleep(0.1)

I want to pass a variable when calling .start such as

self.myLongTask.start(myvar)
.
.
def run(self, myvar):

but of course, pyqt does not allow that.

Community
  • 1
  • 1
electro
  • 911
  • 4
  • 12
  • 28
  • 1
    Is there a reason you would not want to pass the parameter using the signal/slot mechanism once the thread is already started? – paisanco Oct 15 '15 at 02:20
  • As I understood, the signal/slot like the code above is can be used to send param from TaskThread to MyCustomWidget. What I want is to send param from the MyCustomWidget to TaskThread. – electro Oct 15 '15 at 06:39
  • 2
    It is possible to signals/slots both ways, but why not just pass the parameter in at thread instantiation time? – three_pineapples Oct 15 '15 at 09:35
  • It is possible to send both ways? Can you give an example? Thanks! The reason is I want to pass new value of the param passed each time I start the thread. That new value will be processed by the thread run(). – electro Oct 15 '15 at 18:30
  • @electro Sorry about this being 4 months late. I hadn't forgotten your request for an example. [This](http://stackoverflow.com/a/35534047/1994235) answer I just wrote demonstrates similar behaviour. It demonstrates signal emission in both directions. You would just need to modify it to pass a parameter when the signals are emitted in the desired direction. – three_pineapples Feb 21 '16 at 08:44

1 Answers1

7

You can not pass argument to run but you can pass argument to it's constructor like this:

class TaskThread(QtCore.QThread):
    notifyProgress = QtCore.pyqtSignal(int)
    def __init__(self, myvar, parent=None):
        QThread.__init__(self, parent)
        self.myvar = myvar
    def run(self):
        #use self.myvar in your run 
        for i in range(101):
            self.notifyProgress.emit(i)
            time.sleep(0.1)

and in the MyCustomWidget class:

class MyCustomWidget(QtGui.QWidget):

    def __init__(self, parent=None):
        super(MyCustomWidget, self).__init__(parent)
        layout = QtGui.QVBoxLayout(self)       

        self.progressBar = QtGui.QProgressBar(self)
        self.progressBar.setRange(0,100)
        button = QtGui.QPushButton("Start", self)
        layout.addWidget(self.progressBar)
        layout.addWidget(button)

        button.clicked.connect(self.onStart)
        ##############################################################
        #and pass your argumetn to it's constructor here
        self.myLongTask = TaskThread(myvar=myargument)
        ##############################################################
        self.myLongTask.notifyProgress.connect(self.onProgress)


    def onStart(self):
        self.myLongTask.start()

    def onProgress(self, i):
        self.progressBar.setValue(i)
Steven C. Howell
  • 16,902
  • 15
  • 72
  • 97
Habib Kazemi
  • 2,172
  • 1
  • 24
  • 30
  • 1
    Thanks for the code. It actually gives out error: AttributeError: 'PyQt4.QtCore.pyqtSignal' object has no attribute 'connect' But if we move the self.notifyProgress = QtCore.pyqtSignal(int) outside and above __init__, it works. – electro Oct 16 '15 at 02:20