How to pass arguments to functions by the click of button in PyQt?
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
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!
![Admin](/assets/logo_square_200-5d0d61d6853298bd2a4fe063103715b4daf2819fc21225efa21dfb93e61952ea.png)
Admin
Updated on July 09, 2022Comments
-
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; soname
value will vary. So I want to attach each name with the button. I have done same thing in Pytk by usingfor
loop and calling the argument base function when clicked. -
Admin almost 13 yearsThanks 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 almost 8 years+1; the calluser-Function can also access any methods or attributes via self.* This works, where lambda functions fail!
-
aoh over 6 years@LuWi Do you know why the lambda functions fail?
-
LuWi over 6 yearsI guess it has something to do with scopes, but I'm not entierly sure. I was glad to get it working ;)
-
komodovaran_ about 6 yearsIt doesn't seem to work if the input argument changes. E.g.
button.clicked.connect(partial(self.function, self.currentSelection))
ifself.currentSelection
is changed. Then you should set the argument inside the function viaself
, or create a nested function. -
NinjasAtWork almost 5 yearsvery elegant :D
-
NinjasAtWork almost 5 yearsEven More elegant! loved it!
-
magamig about 4 yearsif the above does not work (for example inside a loop), do this: button.clicked.connect(lambda state, x=name: calluser(x))
-
SALMAANYEHIA almost 4 yearsYour answer is exactly what I was looking for... Thank you so much!
-
Julius almost 3 yearsHas 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 almost 3 yearsPerfect solution!
-
payala over 2 years@magamig why does the above not work inside a loop?
-
ozcanyarimdunya over 2 yearseach 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