Каковы ограничения функций обратного вызова, связанных со следами Tkinter? - PullRequest
4 голосов
/ 26 марта 2012

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

Рассмотрим следующий код Python:

from Tkinter import *

def callbackfunc(*args):
  print "Hello World!"

class App:

  def __init__(self, master):
    frame = Frame(master)
    frame.pack()

    optionvalue = IntVar(master)
    optionvalue.set(2)
    optionvalue.trace("w", callbackfunc)
    self.optionmenu = OptionMenu(master, optionvalue, 1, 2, 3, 4)
    self.optionmenu.pack()

Я пытаюсь реализовать OptionMenu (виджет Tkinter) так, чтобы при изменении его выбранного значения моя функция обратного вызова делала что-то значимое - более конкретно, она изменяла значение глобальной переменной, определенной где-то еще в программе,Как это реализовано выше, он просто печатает выходные данные (хотя и успешно).

Я не могу понять, как передать параметры в мою функцию обратного вызова.Я не хочу, чтобы эта конкретная функция обратного вызова возвращала что-либо;однако мне любопытно, как заставить мою функцию обратного вызова возвращать что-то, и как я буду реализовывать остальную часть моей программы, чтобы она могла использовать эти возвращенные результаты, какими бы они ни были.Пытаюсь ли я реализовать функцию обратного вызова Python таким образом, чтобы она не была предназначена для реализации?Если нет, то как мне заставить это работать?

Ответы [ 3 ]

4 голосов
/ 26 марта 2012

Немного неясно, что вы подразумеваете под "передачей параметров моей функции обратного вызова". Вы уже делаете это! Например:

from Tkinter import *

def callbackfunc(*args, **kwargs):
    print args, kwargs
    print "Hello World!"

class App(object):
    def __init__(self, master):
        frame = Frame(master)
        frame.pack()

        optionvalue = IntVar(master)
        optionvalue.set(2)
        optionvalue.trace("w", callbackfunc)
        self.optionmenu = OptionMenu(master, optionvalue, 1, 2, 3, 4)
        self.optionmenu.pack()

root = Tk()
app = App(root)
root.mainloop()

При запуске ...

$ python foo.py 
('PY_VAR0', '', 'w') {}
Hello World!

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

from Tkinter import *

class App(object):
    def __init__(self, master):
        frame = Frame(master)
        frame.pack()

        optionvalue = IntVar(master)
        optionvalue.set(2)
        optionvalue.trace("w", self.callbackfunc)
        self.optionmenu = OptionMenu(master, optionvalue, 1, 2, 3, 4)
        self.optionmenu.pack()
        self.state = []

    def callbackfunc(self, *args):
        self.state.append(args)
        print self.state


root = Tk()
app = App(root)
root.mainloop()

При запуске ...

$ python foo.py 
[('PY_VAR0', '', 'w')]
[('PY_VAR0', '', 'w'), ('PY_VAR0', '', 'w')]
[('PY_VAR0', '', 'w'), ('PY_VAR0', '', 'w'), ('PY_VAR0', '', 'w')]

Также, возможно, вы хотите получить доступ к значению optionvalue. Тогда вы можете сохранить ссылку на него:

from Tkinter import *

class App(object):
    def __init__(self, master):
        frame = Frame(master)
        frame.pack()

        self.optionvalue = IntVar(master)
        self.optionvalue.set(2)
        self.optionvalue.trace("w", self.callbackfunc)
        self.optionmenu = OptionMenu(master, self.optionvalue, 1, 2, 3, 4)
        self.optionmenu.pack()
        self.state = []

    def callbackfunc(self, *args):
        self.state.append(args)
        print self.state
        print self.optionvalue.get()


root = Tk()
app = App(root)
root.mainloop()

При запуске ...

$ python foo.py 
[('PY_VAR0', '', 'w')]
1
[('PY_VAR0', '', 'w'), ('PY_VAR0', '', 'w')]
2
[('PY_VAR0', '', 'w'), ('PY_VAR0', '', 'w'), ('PY_VAR0', '', 'w')]
3

Вы также можете использовать root.getvar(name) с name = 'PY_VAR0' (первый аргумент, переданный обратному вызову), как подсказывает noob oddy .

2 голосов
/ 26 марта 2012

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

определите ваш обратный вызов, как хотите:

def callbackfunc(message=None):
  print message

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

    optionvalue.trace("w", lambda name, index, op, 
                      message="hello, world": callbackfunc(message))

Вы также можете использовать functools.partial, чтобы сделать то же самое в возможно более удобном для чтения синтаксисе.

1 голос
/ 26 марта 2012
from Tkinter import *

def callbackfunc(name, index, mode):
    print root.getvar(name)

class App:

    def __init__(self, master):
        frame = Frame(master)
        frame.pack()

        optionvalue = IntVar(master)
        optionvalue.set(2)
        optionvalue.trace("w", callbackfunc)
        self.optionmenu = OptionMenu(master, optionvalue, 1, 2, 3, 4)
        self.optionmenu.pack()

root = Tk()
app = App(root)
root.mainloop()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...