如何在PyQt中通过按钮点击将参数传递给函数?

65

我希望在点击按钮时将参数传递给函数。 我应该在这行中添加什么 button.connect(button, QtCore.SIGNAL('clicked()'), calluser(name)) 以便它将值传递给函数:

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

还有一件事,按钮将使用for循环生成;因此name值会有所不同。因此,我想将每个名称与按钮相关联。在Pytk中,我使用for循环完成了相同的操作,并在单击时调用了参数基础函数。


1
你需要在某个地方设置变量“name”...它是在哪里被设置的? - Tom Studee
1
Lambda方法对我很有效,并且保持了Qt程序的结构:https://stackoverflow.com/a/53928495/7944058 - Casey
7个回答

121
你可以简单地写。
name = "user"
button.clicked.connect(lambda: calluser(name))

3
更加优雅了!喜欢它! - NinjasAtWork
26
如果以上方法不起作用(例如在循环内),请执行以下操作: button.clicked.connect(lambda state, x=name: calluser(x)) 注:该句为Python代码,意为当按钮被点击时,调用一个名为calluser的函数,并将变量x的值设为name的值。其中lambda表达式用于创建一个匿名函数。 - magamig
2
你的回答正是我所需要的...非常感谢! - SALMAANYEHIA
完美的解决方案! - jaw12346
每次信号都将被分配给相同的函数,循环结束时,最后一个项目将被分配给方法。这就是为什么它在循环内部不起作用,你应该考虑不同的逻辑。 - ozcanyarimdunya
显示剩余2条评论

40

通常使用类来构建GUI界面。通过使用绑定方法作为回调函数(见下面的self.calluser),您可以通过self的属性(例如self.name)将信息“传递”给回调函数:

例如,使用稍微修改过的代码自这个教程

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

由于回调函数本身始终不带任何附加参数,当您需要向多个回调传递不同的附加信息时,您需要为每个按钮制作不同的回调函数。

由于手动完成这一过程可能很繁琐,因此请改用函数工厂。以下是一个示例。函数工厂是一个闭包,它可以传递额外的参数,内部函数在调用时可以访问这些参数:

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_()

1
谢谢回复,但在我的情况下,名称的值将随着按钮由for循环生成而更改。所以我可以将值作为参数传递给函数吗? - uahmed
2
+1;通过self.*,calluser函数还可以访问任何方法或属性。这很有效,而lambda函数就无法做到! - LuWi
@LuWi 你知道为什么Lambda函数会失败吗? - aoh
我猜这可能与作用域有关,但我并不完全确定。我很高兴它能够正常工作 ;) - LuWi

40

我尝试了一种高效的方法,对我来说效果很不错。你可以使用以下代码:

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

2
非常优雅 :D - NinjasAtWork
5
有人在点赞之前尝试过使用多个名称吗?部分会冻结名称。也就是说,一旦将其设置为“用户”,您无法通过GUI更改它。 - Julius

6
在Python中,类实例是可调用的。您可以将一个类的实例作为函数使用。该类可以包含任何内容。(在某些语言或框架中,可调用对象被称为functor或函数对象。)
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!

5

这里还有一种方法。- 部分 - 我认为这是最简单的方法:

    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

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

这是一个关于在PyQt和Maya中将参数传递到函数并将其连接到PyQt按钮的方法的讨论。

2
如果输入参数发生更改,它似乎无法正常工作。例如,button.clicked.connect(partial(self.function, self.currentSelection)) 如果 self.currentSelection 发生更改,则应通过 self 在函数内设置参数,或创建一个嵌套函数。 - komodovaran_

0

你也可以使用参数,

button.cliked.connect(lambda self.change_value( "extra"))

函数

def change_value( extraVariable):
     print( extraVariable)

有没有漏掉 c:?应该是这样的:button.clicked.connect(lambda: self.change_value("extra")) 我也没看到与 @ozcanyarimdunya 在2019年的回答有什么新的不同。 - theozh

0
下面的代码演示了一种将数据与生成的按钮关联的方法。例如,您可以更改语句self.keydata[b] = key,将数据元组存储到self.keydata[b]中,以便在稍后处理按钮事件时使用。
请注意,在以下代码中,assets是先前定义的包含按钮标题的字典。在processButton(self)例程中,self.sender()等于类变量buttons[]中的一个条目。
class Tab5(QtGui.QWidget):
    buttons, keydata = {}, {}
    def __init__(self, fileInfo, parent=None):
        super(Tab5, self).__init__(parent)
        layout = QtGui.QVBoxLayout()

        for key in sorted(assets):
            b = self.buttons[key] = QtGui.QPushButton(assets[key], self)
            b.clicked.connect(self.processButton)
            layout.addWidget(b)
            print 'b[key]=',b, ' b-text=',assets[key]
            self.keydata[b] = key

        layout.addStretch(1)
        self.setLayout(layout)

    def processButton(self):
         print 'sender=',self.sender(), ' s-text=',self.sender().text(), ' data[.]=', self.keydata[self.sender()] 
         pass

输出结果如下,前四行在for循环期间打印,后四行在按顺序按下四个按钮时打印。

b[key]= <PySide.QtGui.QPushButton object at 0x7f382f2ca830>  b-text= K1
b[key]= <PySide.QtGui.QPushButton object at 0x7f382f2ca908>  b-text= K2
b[key]= <PySide.QtGui.QPushButton object at 0x7f382f2ca950>  b-text= K3
b[key]= <PySide.QtGui.QPushButton object at 0x7f382f2ca998>  b-text= K4
sender= <PySide.QtGui.QPushButton object at 0x7f382f2ca830>  s-text= K1  data[.]= L1
sender= <PySide.QtGui.QPushButton object at 0x7f382f2ca908>  s-text= K2  data[.]= L2
sender= <PySide.QtGui.QPushButton object at 0x7f382f2ca950>  s-text= K3  data[.]= L3
sender= <PySide.QtGui.QPushButton object at 0x7f382f2ca998>  s-text= K4  data[.]= L4

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接