evan54
evan54

Reputation: 3733

using threading for a qt application

I have the following two files:

import sys
import time
from PyQt4 import QtGui, QtCore

import btnModule

class WindowClass(QtGui.QWidget):

    def __init__(self):
        super(WindowClass, self).__init__()
        self.dataLoaded = None

#       Widgets

#       Buttons
        thread = WorkerForLoop(self.runLoop)
#        thread.start()
        self.playBtn    = btnModule.playpauselBtnClass \
                            ('Play', thread.start)            
#       Layout
        layout = QtGui.QHBoxLayout()
        layout.addWidget(self.playBtn)
        self.setLayout(layout)

#       Window Geometry
        self.setGeometry(100, 100, 100, 100)

    def waitToContinue(self):
        print self.playBtn.text()
        while (self.playBtn.text() != 'Pause'):
            pass

    def runLoop(self):
        for ii in range(100):
            self.waitToContinue()
            print 'num so far: ', ii
            time.sleep(0.5)

class WorkerForLoop(QtCore.QThread):
    def __init__(self, function, *args, **kwargs):
        super(WorkerForLoop, self).__init__()
        self.function = function
        self.args = args
        self.kwargs = kwargs

    def __del__(self):
        self.wait()

    def run(self):
        print 'let"s run it'
        self.function(*self.args, **self.kwargs)
        return



if __name__ == '__main__':

    app = QtGui.QApplication(sys.argv)

    wmain = WindowClass()
    wmain.show()

    sys.exit(app.exec_())

and the second file btnModule.py:

from PyQt4 import QtGui, QtCore

class playpauselBtnClass(QtGui.QPushButton):

    btnSgn = QtCore.pyqtSignal()

    def __init__(self, btnName, onClickFunction):
        super(playpauselBtnClass, self).__init__(btnName)

        self.clicked.connect(self.btnPressed)
        self.btnSgn.connect(onClickFunction)

    def btnPressed(self):
        if self.text() == 'Play':
            self.setText('Pause')
            self.btnSgn.emit()
            print 'Changed to pause and emited signal'
        elif self.text() == 'Pause':
            self.setText('Continue')
            print 'Changed to Continue'
        elif self.text() == 'Continue':
            self.setText('Pause')
            print 'Changed to Pause'

If in the first file I remove the comment at thread.start() it works as expected, it starts the thread and then hangs until I click Play on the UI. However, I thought it should work even if I didn't start it there as the signal is btnSgn is connected to onClickFunction which in this case takes the value thread.start.

Used this as a reference http://joplaete.wordpress.com/2010/07/21/threading-with-pyqt4/

Upvotes: 0

Views: 128

Answers (1)

Relja Arandjelović
Relja Arandjelović

Reputation: 497

I think the reason it doesn't work when you try to call thread.start() in your second file (via self.btnSgn.emit()) is that the thread object goes out of scope outside of the init function where you created it. So you are calling start() on an already deleted thread.

Just changing thread -> self.thread (i.e. making the thread object a member of the WindowClass object) works fine when I tried it, since thread is then kept alive till the end of the program.

Upvotes: 2

Related Questions