Как вы вызываете функцию переменной трассировки, в которой используется сама переменная - PullRequest
0 голосов
/ 09 января 2020

Я пытаюсь вызвать функцию, когда пользователь нажимает на виджет Checkbox. У меня возникают трудности с этим, поскольку сама переменная трассировки передается в функцию (я понимаю, что передается не сама переменная tkinter, а ее содержимое)

Код

#Image swapping code
mode = tk.IntVar()
checkBox = tk.Checkbutton(root,text=": World Mode",variable = mode)
checkBox.grid(row=3,column=3)
def swapimages(num):
    print(num)
    if num==1:
        imageLabel.configure(image = ukImg)
    else:
        imageLabel.configure(image = worldImg)
mode.trace("w", lambda: swapimages(mode.get()))

Ошибка

Я получаю эту ошибку

TypeError: <lambda>() takes 0 positional arguments but 3 were given

Эта ошибка не возникает, когда я использую лямбду для кнопок, например

generateButton = tk.Button(root,text="Generate!",command=lambda: getLatLong(inputtedPostcode.get()))

Ответы [ 3 ]

1 голос
/ 09 января 2020

Когда вы помещаете трассировку в переменную, tkinter будет вызывать функцию с тремя аргументами. Ваша лямбда должна принимать эти аргументы, даже если вы их не используете.

Поскольку вы не используете аргументы, вы можете определить свою лямбду следующим образом:

mode.trace("w", lambda *args: swapimages(mode.get()))

Другое решение это прямой вызов вашей функции, и ваша функция должна использовать аргументы. Например, первый аргумент - это имя переменной. Вы можете использовать функцию getvar в окне root, чтобы получить значение виджета по имени.

Пример:

def swapimages(varname, _, operation):
    num = root.getvar(varname)
    print("num:", num)
mode.trace("w", swapimages)

Для получения дополнительной информации о аргументах см. Каковы аргументы для обратных вызовов метода трассировки переменных Tkinter?

Все это говорит о том, что виджет checkbutton может напрямую вызывать функцию при изменении значения, не полагаясь на отслеживание переменных. Это наиболее распространенный способ выполнения функции при нажатии кнопки-флажка.

Пример:

def swapimages():
    num = mode.get()
    print("num:", num)

checkBox = tk.Checkbutton(root,text=": World Mode", 
                          onvalue=1, offvalue=0, variable=mode,
                          command=swapimages)
0 голосов
/ 09 января 2020

При использовании обратного вызова в вызове trace, callback должен иметь возможность принимать 3 аргумента со стороны "tkinter". Вы можете изменить его так, чтобы он принимал ваши собственные аргументы, если вы используете sh, но он должен принять как минимум 3 от tkinter.

Чтобы увидеть, что это за аргументы, мы можем проверить документацию или провести быструю проверку по приведенному ниже примеру:

import tkinter as tk

def swap_images(*args):
    print(f"I was passed {len(args)} arguments")
    for n, arg in enumerate(args):
        print(f"Arg {n}: {arg}")

root = tk.Tk()
mode = tk.StringVar(master=root, value="Hello", name="I'm the mode var!")
mode_entry = tk.Entry(master=root, textvariable=mode)
mode_entry.pack()
mode.trace("w", lambda *args: swap_images(*args))
root.mainloop()

Вывод из swap_images функция (при изменении записи):

I was passed 3 arguments
Arg 0: I'm the mode var!
Arg 1:
Arg 2: w

Мы легко видим, что первый аргумент - это внутреннее имя переменной, а третий - выполняемая операция (w riting).

Этого, наряду с этим упоминанием из документации, которую я связал выше, достаточно, чтобы выяснить, что является вторым аргументом:

Когда трассировка срабатывает, три аргумента добавляются к commandPrefix так что фактическая команда выглядит следующим образом:

commandPrefix name1 name2 op

name1 и name2 дают имя (имена) для доступ к переменной: если переменная является скаляром, то name1 дает имя переменной, а name2 - пустая строка; если переменная является элементом массива, то name1 дает имя массива, а name2 дает индекс в массиве; если удаляется весь массив и трасса была зарегистрирована в общем массиве, а не в одном элементе, то name1 дает имя массива, а name2 - пустое строка. name1 и name2 не обязательно совпадают с именем, используемым в команде переменной переменной: команда upvar позволяет процедуре ссылаться на переменную под другим именем.

op указывает, какая операция выполняется с переменной, и является одной из операций чтения, записи или сброса, как определено выше.

Так что это значит для вас?

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

Изменить

mode.trace("w", lambda: swapimages(mode.get()))

до

mode.trace("w", lambda *args: swapimages(mode.get()))

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

0 голосов
/ 09 января 2020

Функции обратного вызова для .trace() должны принимать три аргумента, ваша лямбда не принимает никаких.

Измените вашу лямбду следующим образом, чтобы принимать произвольное количество аргументов:

mode.trace("w", lambda *args: swapimages(mode.get()))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...