Похоже, вы пытаетесь создать графический интерфейс, который действует процедурно, который не будет работать.GUI не являются процедурными, их код не работает линейно, когда функции вызывают обратные вызовы, которые возвращают значения.То, что вы спрашиваете, не уникально для tkinter.Такова природа основанного на событиях программирования GUI - обратные вызовы не могут ничего возвратить, потому что вызывающая сторона - это событие, а не функция.
Грубо говоря, вы должны использовать глобальный объекткакой-то вид для хранения ваших данных.Обычно это называется «Модель».Это может быть глобальная переменная, база данных или какой-либо объект.В любом случае, он должен существовать «глобально»;то есть он должен быть доступен всему графическому интерфейсу.
Часто этот доступ предоставляется третьим компонентом, называемым «Контроллер».Это интерфейс между GUI («Вид») и данными («Модель»).Эти три компонента составляют то, что называется шаблоном модель-представление-контроллер, или MVC.
Модель, вид и контроллер не должны быть тремя разными объектами.Часто графический интерфейс и контроллер - это один и тот же объект.Для небольших программ это работает довольно хорошо - компоненты GUI взаимодействуют напрямую с вашей моделью данных.
Например, у вас может быть класс, представляющий окно, которое наследуется от Tkinter.Toplevel.Он может иметь атрибут, который представляет редактируемые данные.Когда пользователь выбирает «Новый» в главном окне, он делает что-то вроде self.tileset = TileSet(filename)
.То есть он устанавливает атрибут с именем tileset
объекта графического интерфейса с именем self
как экземпляр класса TileSet
, специфичный для данного имени файла.Более поздние функции, которые манипулируют данными, используют self.tileset
для доступа к объекту.Для функций, которые находятся вне объекта главного окна (например, функция «сохранить все» из главного окна), вы можете либо передать этот объект в качестве аргумента, либо использовать объект окна в качестве контроллера, попросив его сделать что-то для его объекта.Tileset.
Вот краткий пример:
import Tkinter as tk
import tkFileDialog
import datetime
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.windows = []
menubar = tk.Menu(self)
self.configure(menu=menubar)
fileMenu = tk.Menu(self)
fileMenu.add_command(label="New...", command=self.new_window)
fileMenu.add_command(label="Save All", command=self.save_all)
menubar.add_cascade(label="Window", menu=fileMenu)
label = tk.Label(self, text="Select 'New' from the window menu")
label.pack(padx=20, pady=40)
def save_all(self):
# ask each window object, which is acting both as
# the view and controller, to save it's data
for window in self.windows:
window.save()
def new_window(self):
filename = tkFileDialog.askopenfilename()
if filename is not None:
self.windows.append(TileWindow(self, filename))
class TileWindow(tk.Toplevel):
def __init__(self, master, filename):
tk.Toplevel.__init__(self, master)
self.title("%s - Tile Editor" % filename)
self.filename = filename
# create an instance of a TileSet; all other
# methods in this class can reference this
# tile set
self.tileset = TileSet(filename)
label = tk.Label(self, text="My filename is %s" % filename)
label.pack(padx=20, pady=40)
self.status = tk.Label(self, text="", anchor="w")
self.status.pack(side="bottom", fill="x")
def save(self):
# this method acts as a controller for the data,
# allowing other objects to request that the
# data be saved
now = datetime.datetime.now()
self.status.configure(text="saved %s" % str(now))
class TileSet(object):
def __init__(self, filename):
self.data = "..."
if __name__ == "__main__":
app = SampleApp()
app.mainloop()