简体   繁体   English

将许多按钮绑定到函数,将每个按钮的名称作为参数传递

[英]Binding many buttons to a function, passing each button's name as an argument

Note that my problem is the opposite of this: Creating functions in a loop in that I have many buttons and one function, not many functions. 请注意,我的问题与此相反: 在循环创建函数 ,因为我有许多按钮和一个函数,而不是很多函数。

I create 10 numbered buttons from a for loop, then try to bind each one to a function that will print the button's number; 我从for循环创建10个编号按钮,然后尝试将每个按钮绑定到一个将打印按钮编号的函数; See code below: 见下面的代码:

import tkinter as tk

class Window(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)

        # creating buttons and adding them to dictionary

        self.buttons = {}
        for number in range(1, 11):
            self.buttons.update({'button' + str(number): tk.Button(self, height=1, width=4, bg="grey", text=number)})

        # example of a pair in the dictionary: 'button2': <Tkinter.Button instance at 0x101f9ce18>


        """ bind all the buttons to callback, each button is
            named something like 'button3',so I take the number off
            the end of its name and feed that as an argument to Callback"""

        for button in self.buttons:
            self.buttons[button].bind('<Button-1>', lambda event: self.Callback(event, button[6:]))
            self.buttons[button].pack(side='left')

    def Callback(self, event, num):
        print(num)

All the buttons appear on the window no problem, but when I click any of them, the console prints ' 10 ', as opposed to the button's number. 窗口上显示的所有按钮都没有问题,但是当我点击它们中的任何一个时,控制台会打印“ 10 ”,而不是按钮的编号。 It seems the function is only remembering the last argument it was given. 似乎该函数只记住它给出的最后一个参数。

First lets correct your code to give the desired answer. 首先,让我们更正您的代码,以提供所需的答案。

import tkinter as tk

class Window(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)

        self.buttons = {}
        for number in range(1, 11):
            self.buttons.update({'button' + str(number): tk.Button(self, height=1, width=4, bg="grey", text=number)})

        for button in self.buttons:
            self.buttons[button].bind('<Button-1>', lambda event, num=button[6:]: self.Callback(event, num))
            self.buttons[button].pack(side='left')               #\____________/

    def Callback(self, event, num):
        print(num)

Window().mainloop()

Explanation : 说明

The trick lies in the way lambda functions work. 诀窍在于lambda函数的工作方式。

When you write lambda event: self.Callback(event, button[6:]) , it doesn't get the value of button[6:] at that instance and store it. 当你编写lambda event: self.Callback(event, button[6:]) ,它不会获得该实例的button[6:]的值并存储它。 Instead, it makes a closure , which is sort of like a note to itself saying " I should look for what the value of the variable button(the iterator) is at the time that I am called ". 相反,它会产生一个闭包 ,这有点像对自己的说法“ 我应该在我被称为时应该查找变量按钮(迭代器)的值 。“

Now when the loop is over and every widget is ready and set up, and you call it, it will look for the value of button at that time, which is ofcourse the last value of the iteration (here, button10 ). 现在当循环结束并且每个小部件都准备好并设置好,并且你调用它时,它将在那时查找按钮的值,这当然是迭代的最后一个值(这里是button10 )。

num=button[6:] causes the function to store the current value of the counter(here button ) at the time your lambda is defined, instead of waiting to look up the value of button later. num=button[6:]使函数在定义lambda时存储计数器的当前值(此处为按钮 ),而不是等待稍后查找按钮的值。

Credits: BrenBarn 致谢: BrenBarn


Just to add, you can do what you are doing right now in much less code using the command attribute of Button widget. 只是添加,您可以使用Button小部件的command属性以更少的代码执行您正在执行的操作。 Here is an example. 这是一个例子。

import tkinter as tk

class Window(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)

        for number in range(1, 11):
            tk.Button(self, height=1, width=4, bg="grey", text=number, command=lambda num=number: self.Callback(num)).pack(side='left')

    def Callback(self, num):
        print(num)

Window().mainloop()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM