Вопрос по return, callback, python, tkinter – Python - возвращение из обратного вызова Tkinter

4

Как я могу получить возвращенный объект из функции, которая выполняется как обратный вызов Tkinter?

import Tkinter as Tk
from functools import partial

def square(x):
    return x*x

root = Tk.Tk()
var = Tk.IntVar(root, value=0) #the variable the gets passed to the class call
menu = Tk.OptionMenu(root, var, *[0,1,2,3,4,5]) #a drop-down list to choose a value for the variable
menu.pack()
button = Tk.Button(root, text='click', command = partial(square,var.get())) #a button that calls the class
button.pack()
root.mainloop()

Очевидно, это упрощенный пример. В действительности функция, вызываемая кнопкой, будет возвращать объекты, которые я хочу добавить в список объектов, которые будут храниться в основном пространстве имен Python для дальнейших операций.

В любом случае, здесь пользователь может выбрать аргумент для функции, используя графический интерфейс, и нажать кнопку, которая будет выполнять функцию. Однако возвращаемое значение функции, похоже, обречено на потерю в эфире, поскольку обратный вызов не принимает возвраты. Можно ли это преодолеть без использования уродливогоglobal в определенииsquare(x)?

На самом деле, я думаю, что призыв кvar.get() внутриpartial может на самом деле не работать, поскольку он будет оцениваться при создании кнопки, а не при ее нажатии. Не позволяйте этому облаку решить проблему - мой вопрос действительно о возвращении изsquare(x) в кнопку. Benjamin Hodgson♦
Вы можете обойти это, заменив вызовpartial сlambda функция:command = lambda x=var.get(): square(x), Вы также можете настроитьvar.trace(). Benjamin Hodgson♦

Ваш Ответ

3   ответа
0

которая вызывается вашей кнопкой, вместо того, чтобы помещать все это в строку.

button=Tk.Button(parent, text='click', command=someFxn)

def someFxn(): your code

Затем в своей функции просто вызовите var.get (), выполните вычисления, а затем сделайте что-нибудь со значением.

8

онтексте программы, управляемой событиями. Обратные вызовы вызываются как результат события, поэтому возвращать значение некуда.

Как правило, ваши обратные вызовы всегда должны вызывать функцию, а не использоватьfunctools.partial или жеlambda, Эти два хороши, когда необходимо, но если вы используете объектно-ориентированный стиль кодирования, они часто не нужны и приводят к коду, который сложнее поддерживать, чем нужно.

Например:

def compute():
    value = var.get()
    result = square(value)
    list_of_results.append(result)

button = Tk.Button(root, text='click', command = compute)
...

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

class App(...):
    ...
    def compute():
        ...
        result = self.square(self.var.get())
        self.results.append(result)
list_of_results.append() линия в вашем первом примере делает меня немного брезгливым. Странно, что функция изменяет переменные вне своей области, независимо от того, явно ли вы это называетеglobal переменная. Реализация всей программы как класса - хорошая идея. Benjamin Hodgson♦
@poorsod: нет другого выбора, кроме как изменить переменные за пределами локальной области видимости. Вот как работают графические интерфейсы. Как я уже сказал, обратные вызовы не могут возвращать значения своему вызывающему, потому что у них нет вызывающего (кроме цикла обработки событий). Однако, когда вы думаете о обратном вызове, происходящем в области объекта приложения, это имеет больше смысла. Обратный вызов - это просто изменение атрибута своего собственного объекта.
3

но недавно я нашел хороший способ сделать это, не делая ваш код грязным и сложным в обслуживании. Это в значительной степени то, чтоDaveTheScientist сказал, но я просто хочу рассказать об этом немного. Обычно в Tkinter, если вы хотите, чтобы кнопка вызывала функцию, вы делаете следующее:

exampleButton = Button(root, text = 'Example', command = someFunc)

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

exampleButton = Button(root, text = 'Example', command = lambda: someFunc(arg1, arg2))

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

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

def buttonpress(function, *args):
    value = function(*args)

Затем, когда вы создаете кнопку, вы делаете:

exampleButton = Button(root, text = 'Example', command = lambda: buttonpress( someFunc, arg1, arg2 ))

Это запустит данную функцию (в этом случаеsomeFunc) и сохраните возвращенное значение вvalue переменная. Он также имеет то преимущество, что вы можете использовать столько аргументов, сколько хотите для функции, которую запускает ваша кнопка.

Похожие вопросы