Search code examples
pythonmultithreadingpyqtqthread

PyQt how to send/recieve signals between threads


Hi all and thanks for the help.

I am using a PyQt GUI to read and write voltages to mass flow controls and a heat flux gage. I am using QThreads to have a thread running in the background continuously updating the measurements displayed in the GUI. I am running into trouble having the background thread actually update the GUI as it does not have access to the GUI thread's functions. From what I have read online there is something about "moving" on thread into the other but am not sure what is meant by this. Can someone clarify this/point me in the right direction?

Here is my code:

from PyQt4 import QtGui, QtCore
import sys
import design4
import piplates.DAQC2plate as DAQC2
import time
import threading

air = 0.0
propane = 0
tolerance = .1
n = 1 #number of air controllers

class App4(QtGui.QMainWindow, design4.Ui_MainWindow):
    def __init__(self, parent =None):

        super(self.__class__, self).__init__()
        self.setupUi(self)
        self.sendFlow.clicked.connect(self.inputClicked)
        self.displayFlow.clicked.connect(self.outputClicked)
        self.hfButton.clicked.connect(self.heatFluxRead)

        self.myThread = Worker()
        self.myThread.start()

    def inputClicked(self):

        air = float(self.AirFlowInput.text())
        propane = self.PropaneFlowInput.text()

        if air <= 160 and air > 0:
            acv = air / 20.0 / n *2 +.05#compute air control voltage for each controller
            DAQC2.setDAC(0,0,acv) #changing voltage signal for channel 0
            DAQC2.setDAC(0,1,acv)
        else:
            DAQC2.setDAC(0,0,0)

        print DAQC2.getDAC(0,1)
        print DAQC2.getDAC(0,0)

    def outputClicked(self):

        airRead = float(DAQC2.getADC(0,0)-.01) * 40 / n #converting 0-4Volts to flow
        self.airFlowMeasured.display(airRead)


        #print DAQC2.getADC(0,0)

        #propRead = float(DAQC2.getADC(0,2)-.01) * 20
        #self.propaneFlowMeasured.display(propRead)


        #print DAQC2.getADC(0,1)

        #palette = self.airFlowMeasured.palette()
        #role = self.airFlowMeasured.backgroundRole()
        #if float(DAQC2.getADC(0,0)) < (air*(1-tolerance):
         #                            palette.setColor(role, QColor('yellow'))
        #else if

    def heatFluxRead(self):

        heatFlux = float(DAQC2.getADC(0,7)) * 5800.0 #converts volts to kW/m^2
        self.hfNumber.display(heatFlux)

        print heatFlux
        print self.getADC2(0,7)

    def getADC2(self,addr,channel):
        DAQC2.VerifyADDR(addr)
        DAQC2.VerifyAINchannel(channel) 
        resp= DAQC2.ppCMD(addr,0x30,channel,0,2)
        value=(256*resp[0]+resp[1])
        if (channel==8):
            value=value*5.0*2.4/65536
        else:
            value=(value*24.0/65536)-12.0
            value=round(value*DAQC2.calScale[addr][channel]+DAQC2.calOffset[addr][channel],5)
        return value


def main():

    app = QtGui.QApplication(sys.argv)
    form = App4()
    form.show()

    app.exec_()




class Update(QtCore.QObject):
    sendUpdate = QtCore.pyqtSignal()

class Worker(QtCore.QThread):

    def __init__(self, parent = None):

        QtCore.QThread.__init__(self, parent)

        self.initSignal()

    def initSignal(self):      

        self.u = Update()
        self.u.sendUpdate.connect(self.outputClicked)       


    def run(self):

        while True:
            self.u.sendUpdate.emit()
            print 1
            time.sleep(.25)



if __name__ == '__main__':
    main()

Thanks a ton for any help!


Solution

  • I think that reading through DAQC2.getADC() function does not consume much time so it is not necessary to use threads, what you want to do is a periodic task, so the most appropriate option is to use QTimer:

    class App4(QtGui.QMainWindow, design4.Ui_MainWindow):
        def __init__(self, parent =None):
    
            super(self.__class__, self).__init__()
            self.setupUi(self)
    
            self.timer = QtCore.QTimer(self)
            self.timer.timeout.connect(self.outputClicked)
            self.timer.setInterval(250)
    
            self.sendFlow.clicked.connect(self.inputClicked)
            self.displayFlow.clicked.connect(self.timer.start)
            self.hfButton.clicked.connect(self.heatFluxRead)
    
        def inputClicked(self):
    
            air = float(self.AirFlowInput.text())
            propane = self.PropaneFlowInput.text()
    
            if air <= 160 and air > 0:
                acv = air / 20.0 / n *2 +.05#compute air control voltage for each controller
                DAQC2.setDAC(0,0,acv) #changing voltage signal for channel 0
                DAQC2.setDAC(0,1,acv)
            else:
                DAQC2.setDAC(0,0,0)
    
            print DAQC2.getDAC(0,1)
            print DAQC2.getDAC(0,0)
    
        def outputClicked(self):
    
            airRead = float(DAQC2.getADC(0,0)-.01) * 40 / n #converting 0-4Volts to flow
            self.airFlowMeasured.display(airRead)
    
    
            #print DAQC2.getADC(0,0)
    
            #propRead = float(DAQC2.getADC(0,2)-.01) * 20
            #self.propaneFlowMeasured.display(propRead)
    
    
            #print DAQC2.getADC(0,1)
    
            #palette = self.airFlowMeasured.palette()
            #role = self.airFlowMeasured.backgroundRole()
            #if float(DAQC2.getADC(0,0)) < (air*(1-tolerance):
             #                            palette.setColor(role, QColor('yellow'))
            #else if
    
        def heatFluxRead(self):
    
            heatFlux = float(DAQC2.getADC(0,7)) * 5800.0 #converts volts to kW/m^2
            self.hfNumber.display(heatFlux)
    
            print heatFlux
            print self.getADC2(0,7)
    
        def getADC2(self,addr,channel):
            DAQC2.VerifyADDR(addr)
            DAQC2.VerifyAINchannel(channel) 
            resp= DAQC2.ppCMD(addr,0x30,channel,0,2)
            value=(256*resp[0]+resp[1])
            if (channel==8):
                value=value*5.0*2.4/65536
            else:
                value=(value*24.0/65536)-12.0
                value=round(value*DAQC2.calScale[addr][channel]+DAQC2.calOffset[addr][channel],5)
            return value