[PyKDE] Sending an argument to a function with a button click

Christian Bird cbird at byu.edu
Thu Aug 7 00:54:01 BST 2003


I've found a solution that works for me when I have similar problems.  The 
issue is that the connect function call needs to take a callable object and 
self.printMessage("Testing") returns None (which is not a callable object).  
You want the call to evaluate at signal time and not at connect time.  I'm 
attaching a class that I'll call curry.  If your familiar with functional 
programming then the idea of currying will be familiar to you.  If not, just 
think of it as combining a function with some arguments and returning another 
function that remembers the original arguments when called.  Here's an 
example.  Suppose you have two buttons and you want to connect them to a 
single slot, but you want to know which button was pressed when the slot is 
executed:

#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)

class foo(QObject):

	def __init__(self...):
		setup stuff
		self.connect(self.button1, SIGNAL("clicked()"), 
Curry(self.buttonClickedSlot, "button1"))
		self.connect(self.button2, SIGNAL("clicked()"), 
Curry(self.buttonClickedSlot,"button2"))

	def buttonClickedSlot(self, buttonName):
		if buttonName == "button1":
			do stuff
		elif buttonName == "button2":
			do other stuff


In the above example, the same slot gets called when either button is clicked, 
but the text passed to the Curry object is used as an argument when the slot 
is called.  Some signals actually send their own arguments to the slot.  In 
those cases, the signal arguments are added to the list of arguments passed 
to the Curry object and all of them are sent to the slot.

I hope this isn't too confusing.  It's helped me a lot in my PyQt programming.  
Let me know if it helps or if you need further clarification.

Christian Bird
-------

I've started dabbling with PyQt, but I'm a little confused as to how I can 
pass an argument to a function with a button click. For instance, the 
following doesn't work:
(snip button code)

self.connect(self.button1, SIGNAL("clicked()"), self.printMessage("Testing"))

def printMessage(text):
  print text

(etc.)

        Any hints?
        :Peter




More information about the PyQt mailing list