0

I have a small GUI with two simple buttons to access a LabJAck IO module. This module is used to turn on or turn off an external device connected to it. I have written a class that inits the device and several methods to do some things with the device two of which are, turn on and turn off. The reason I am going about accessing the LAbJack this way is because I would like the code to be nice and neat and I will have several devices connected to my machine with each device having specific IO commands.

Here is my code for the LabJAck:

import u3

class LabJack:
    def __init__(self):

        try:
            self.Switch = u3.U3()
        except:
            print "Labjack Error"

        #Define State Registers for RB12 Relay Card

        self.Chan0 = 6008
        Chan1 = 6009
        Chan2 = 6010
        Chan3 = 6011
        Chan4 = 6012
        Chan5 = 6013

    #Turn the channel on
    def IO_On(self,Channel):
        self.Switch.writeRegister(Channel,0)


    #Turn the channel off
    def IO_Off(self,Channel):   
        self.Switch.writeRegister(Channel,1)

    #The State of the Channel
    def StateSetting(self,Channel):
        self.Switch.readRegister(Channel)
        if Switch.readRegister(Channel) == 0:
            print ('Channel is On')
        else:
            print('Channel is Off')

    #Direction of Current Flow
    def CurrentDirection(self,Channel):
        self.Switch.readRegister(6108)
        print self.Switch.readRegister(6108) 

Here is my GUI Code:

import re
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys
from LabJackIO import *
from Piezo902 import *

import ui_aldmainwindow

class ALDMainWindow(QMainWindow,ui_aldmainwindow.Ui_ALDMainWindow):

    def __init__(self, parent=None):
        super(ALDMainWindow,self).__init__(parent) 
        self.setupUi(self)

        self.ValveControl = LabJack()

        self.Valve_ON.clicked.connect(self.ValveControl.IO_On(6008))
       self.Valve_OFF.clicked.connect(self.ValveControl.IO_Off(self.ValveControl.Chan0))
        self.statusBar().showMessage('Valve Off')

app = QApplication(sys.argv)
app.setStyle('motif')
form = ALDMainWindow()
form.show()
app.exec_()

When running the code I get the following error:

Traceback (most recent call last):
  File "ALDSoftwareMainWindow.py", line 26, in <module>
    form = ALDMainWindow()
  File "ALDSoftwareMainWindow.py", line 20, in __init__
    self.Valve_ON.clicked.connect(self.ValveControl.IO_On(6008))
TypeError: connect() slot argument should be a callable or a signal, not 'int'

I cant figure out what I am doing wrong. Any help would be greatly appreciated.

Thanks.

Vivek Dwivedi
  • 89
  • 1
  • 9
  • also see http://stackoverflow.com/questions/18925241/send-additional-variable-during-pyqt-pushbutton-click – tacaswell Sep 23 '13 at 03:34

3 Answers3

1

You are calling the method you are connecting the button to:

self.Valve_ON.clicked.connect(self.ValveControl.IO_On(6008))

Probably this will fix your problem:

self.Valve_ON.clicked.connect(lambda: self.ValveControl.IO_On(6008))

lambda is an anonymous function that will defer the calling of your method IO_ON(6008) until the button is actually clicked.

MadeOfAir
  • 2,933
  • 5
  • 31
  • 39
  • this will work in this case, but beware of tricksy closure traps. – tacaswell Sep 23 '13 at 03:04
  • Like what?. I like tricksy closure traps while I do serious things, I don't know about you.(damn the minimum post length requirement). – MadeOfAir Sep 23 '13 at 03:12
  • See the question linked in my answer. I was doing something like this, but I was generating the `lambda`s from values in a list and ended up only binding the _last_ value of the list. – tacaswell Sep 23 '13 at 03:16
  • and to be clear, I meant traps for you, not traps in the code ;) – tacaswell Sep 23 '13 at 03:17
  • How do you add a self.statusBar().showMessage() to be executed after the Valve_On/Off.clicked.connect as well? – Vivek Dwivedi – Vivek Dwivedi Sep 23 '13 at 22:46
  • If I understand you right, that you want 2 handlers for the Valve_ON button, then you just connect the button to all the handlers you want executed and they will be in turn self.Valve_ON.clicked.connect(lambda: self.statusBar().showMessage('Hello World')) – MadeOfAir Sep 24 '13 at 03:29
1

You have mis-uderstood how slots/signals work. The argument to connect needs to be a function that takes as an argument what ever the signal you are connecting to emits. In this case, it looks like you are connecting to clicked signal from a button (which emits no values). So you need to wrap the function you want to call in a function that takes no arguments. An easy way to do this is to wrap the functions in lambda function:

self.Valve_ON.clicked.connect(lmabda x=6008: self.ValveControl.IO_On(x))
self.Valve_OFF.clicked.connect(lambda x=self.ValveControl.Chan0: self.ValveControl.IO_Off(x))

which creates functions with one optional argument (which defaults the values you want) so it will work as a no-argument slot.

It may seem odd to use the default argument to bind the value in, but it prevents some strange seeming issues with closures (see Python lambda closure scoping)

Another way is to use functools.partial to wrap your functions.

Community
  • 1
  • 1
tacaswell
  • 84,579
  • 22
  • 210
  • 199
1

1 Using partial maybe a best way.

self.Valve_ON.clicked.connect(functools.partial(self.ValveControl.IO_on,6008))

2 Use QSignalMapper.

luxiaolu
  • 111
  • 5