Привязка множества кнопок к функции, передача имени каждой кнопки в качестве аргумента - PullRequest
0 голосов
/ 05 января 2019

Обратите внимание, что моя проблема противоположна этому: Создание функций в цикле в том, что у меня много кнопок и одна функция, а не много функций.

Я создаю 10 пронумерованных кнопок из цикла for, затем пытаюсь привязать каждую из них к функции, которая будет печатать номер кнопки; Смотрите код ниже:

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)

Все кнопки появляются в окне без проблем, но когда я нажимаю любую из них, консоль печатает «10», а не номер кнопки. Кажется, что функция запоминает только последний аргумент, который ей дали.

1 Ответ

0 голосов
/ 05 января 2019

Сначала давайте исправим ваш код, чтобы дать желаемый ответ.

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, <b>num=button[6:]</b>: self.Callback(event, num))
            self.buttons[button].pack(side='left')               #\____________/

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

Window().mainloop()

Объяснение

Хитрость заключается в том, как работают лямбда-функции.

Когда вы пишете lambda event: self.Callback(event, button[6:]), он не получает значение button[6:] в этом экземпляре и не сохраняет его. Вместо этого он создает замыкание , что-то вроде примечания к себе, говорящего: « Я должен посмотреть, каково значение переменной button (итератор) в то время, когда меня называют ».

Теперь, когда цикл закончен и каждый виджет готов и настроен, и вы вызываете его, он будет искать значение кнопки в то время, которое, конечно, является последним значением итерации. (здесь button10).

num=button[6:] заставляет функцию сохранять текущее значение счетчика (здесь кнопка ) во время определения вашей лямбды, вместо ожидания поиска значения кнопка позже.

Кредиты: BrenBarn


Просто добавьте, что вы можете делать то, что делаете сейчас, в гораздо меньшем количестве кода, используя атрибут command виджета Button. Вот пример.

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()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...