jmhobbs

Sending Arbitrary Arguments to a pyQt4 Slot

Okay, so you can't send extra arguments through a slot when you connect it in pyQt4. What I mean by that is if you are connecting to a button's clicked() signal it has zero arguments, so you don't get to send anything to your slot.

This was a really big annoyance, I wanted to send arbitrary arguments defined at connect time. So I looked, and I looked and eventually, I found this treasure. Awesome.

# this creates a class that allows currying of functions
class Curry:
  #keep a reference to all curried instances·
  #or they are immediately garbage collected
  instances = []
  def __init__(self, func, *args, **kwargs):
    self.func = func
    self.pending = args[:]
    self.kwargs = kwargs.copy()
    self.instances.append(self)

  def __call__(self, *args, **kwargs):
    kw = self.kwargs
    kw.update(kwargs)
    funcArgs = self.pending + args
    #sometimes we want to limit the number of arguments that get passed,
    #calling the constructor with the option __max_args__ = n will limit
    #the function call args to the first n items
    maxArgs = kw.get("__max_args__", -1)
    if maxArgs != -1:
        funcArgs = funcArgs[:maxArgs]
        del kw["__max_args__"]
    return self.func(*funcArgs, **kw)

And for usage...

button_1 = QtGui.QPushButton( "Button One" )
QtCore.QObject.connect( button_1, QtCore.SIGNAL( "clicked()" ), Curry( self.myslot, 'Hey, button one!' ) )
button_2 = QtGui.QPushButton( "Button One" )
QtCore.QObject.connect( button_2, QtCore.SIGNAL( "clicked()" ), Curry( self.myslot, 'Word, button two!' ) )

It's just what I needed, this is going into my stash of helpful hints.