How to pass arguments to functions by the click of button in PyQt?

103,411

Solution 1

You can simply write

name = "user"
button.clicked.connect(lambda: calluser(name))

Solution 2

I tried an efficient way of doing it and it worked out well for me. You can use the code:

from functools import partial

def calluser(name):
    print name

def Qbutton():
    button = QtGui.QPushButton("button",widget)
    name = "user"
    button.setGeometry(100,100, 60, 35)
    button.clicked.connect(partial(calluser,name))

Solution 3

Usually GUIs are built using classes. By using bound methods as callbacks (see self.calluser below) you can "pass" information to the callback through self's attributes (e.g. self.name):

For example, using slightly modified code from this tutorial:

import sys
import PyQt4.QtCore as QtCore
import PyQt4.QtGui as QtGui

class QButton(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.button = QtGui.QPushButton('Button', self)
        self.name='me'
        self.button.clicked.connect(self.calluser)
    def calluser(self):
        print(self.name)

def demo_QButton():
    app = QtGui.QApplication(sys.argv)
    tb = QButton()
    tb.show()
    app.exec_()

if __name__=='__main__':
    demo_QButton()

Since the callback per se is always called with no additional arguments, when you need to pass distinct additional information to many callbacks, you need to make different callbacks for each button.

Since that can be laborious (if done manually), use a function factory instead. See below for an example. The function factory is a closure. It can be passed additional arguments, which the inner function can access when called:

class ButtonBlock(QtGui.QWidget):

    def __init__(self, *args):
        super(QtGui.QWidget, self).__init__()
        grid = QtGui.QGridLayout()
        names = ('One', 'Two', 'Three', 'Four', 'Five',
                 'Six', 'Seven', 'Eight', 'Nine', 'Ten')
        for i, name in enumerate(names):
            button = QtGui.QPushButton(name, self)
            button.clicked.connect(self.make_calluser(name))
            row, col = divmod(i, 5)
            grid.addWidget(button, row, col)
        self.setLayout(grid)

    def make_calluser(self, name):
        def calluser():
            print(name)
        return calluser

app = QtGui.QApplication(sys.argv)
tb = ButtonBlock()
tb.show()
app.exec_()

Solution 4

Here is another way. --- PARTIAL -- I find this one most simple:

    widget = QWidget()
    widgetLayout = QVBoxLayout()

    for action in list:

        button = QPushButton("{action}".format(action=action['name']),self)
        button.clicked.connect(partial(self.action_selected,action=action['name']))
        widgetLayout.addWidget(button)

    widget.setLayout(widgetLayout)

def action_selected(self,action):
    print action

found on: http://tech-artists.org/forum/showthread.php?3118-PyQt-Maya-How-to-pass-arguments-to-a-function-when-connecting-it-to-PyQt-button

Solution 5

In Python, class instances are callable. You can just use an instance of a class as a function. That class can contain whatever you want. (In some languages or frameworks, a callable object is called a functor or a function object.)

class CallUser:
    def __init__(self, name):
        self.name = name
    def __call__(self):
        print(self.name)

def Qbutton():
    button = QtGui.QPushButton("button",widget)
    name = "user"
    button.setGeometry(100,100, 60, 35)
    button.clicked.connect(CallUser(name))
    # Object of type CallUser will work as a function!
Share:
103,411
Admin
Author by

Admin

Updated on July 09, 2022

Comments

  • Admin
    Admin almost 2 years

    I want to pass the arguments to a function when I click the button. What should I add to this line button.connect(button, QtCore.SIGNAL('clicked()'), calluser(name)) so it will pass the value to the function:

    def calluser(name):
        print name
    
    def Qbutton():
        button = QtGui.QPushButton("button",widget)
        name = "user"
        button.setGeometry(100,100, 60, 35)
        button.connect(button, QtCore.SIGNAL('clicked()'), calluser(name))
    

    One more thing, buttons will be generated using for loop; so name value will vary. So I want to attach each name with the button. I have done same thing in Pytk by using for loop and calling the argument base function when clicked.

  • Admin
    Admin almost 13 years
    Thanks for the reply, but in my case the value of the name will change as the buttons will be generated by a for loop. So can I pass the values as arguments to the function?
  • LuWi
    LuWi almost 8 years
    +1; the calluser-Function can also access any methods or attributes via self.* This works, where lambda functions fail!
  • aoh
    aoh over 6 years
    @LuWi Do you know why the lambda functions fail?
  • LuWi
    LuWi over 6 years
    I guess it has something to do with scopes, but I'm not entierly sure. I was glad to get it working ;)
  • komodovaran_
    komodovaran_ about 6 years
    It doesn't seem to work if the input argument changes. E.g. button.clicked.connect(partial(self.function, self.currentSelection)) if self.currentSelection is changed. Then you should set the argument inside the function via self, or create a nested function.
  • NinjasAtWork
    NinjasAtWork almost 5 years
    very elegant :D
  • NinjasAtWork
    NinjasAtWork almost 5 years
    Even More elegant! loved it!
  • magamig
    magamig about 4 years
    if the above does not work (for example inside a loop), do this: button.clicked.connect(lambda state, x=name: calluser(x))
  • SALMAANYEHIA
    SALMAANYEHIA almost 4 years
    Your answer is exactly what I was looking for... Thank you so much!
  • Julius
    Julius almost 3 years
    Has anyone actually tried this with multiple names before upvoting? Partial will freeze the name. I.e. once it is set to "user", there is no way you can change it via the GUI.
  • jaw12346
    jaw12346 almost 3 years
    Perfect solution!
  • payala
    payala over 2 years
    @magamig why does the above not work inside a loop?
  • ozcanyarimdunya
    ozcanyarimdunya over 2 years
    each time signal will be assigned to same function, at the end of loop last item will be assigned to method. thats why it doesnt work inside loop, you should think different logic