听起来您正在尝试创建一个按程序执行的 GUI,但这是行不通的。 GUI 不是程序化的,它们的代码不会在函数调用返回值的回调时线性运行。您要问的并不是 tkinter 独有的。这就是基于事件的 GUI 编程的本质——回调不能返回任何东西,因为调用者是事件而不是函数。
粗略地说,您必须使用某种全局对象来存储您的数据。通常这被称为“模型”。它可以是全局变量,也可以是数据库,也可以是某种对象。无论如何,它必须“全球”存在;也就是说,它必须可供整个 GUI 访问。
通常,这种访问是由称为“控制器”的第三个组件提供的。它是 GUI(“视图”)和数据(“模型”)之间的接口。这三个组件构成了所谓的模型-视图-控制器模式,或 MVC。
模型、视图和控制器不必是三个不同的对象。通常,GUI 和控制器是同一个对象。对于小型程序,这非常有效——GUI 组件直接与您的数据模型对话。
例如,您可以有一个表示从 Tkinter.Toplevel 继承的窗口的类。它可以具有表示正在编辑的数据的属性。当用户从主窗口中选择“新建”时,它会执行类似self.tileset = TileSet(filename) 的操作。也就是说,它将名为self 的GUI 对象的名为tileset 的属性设置为特定于给定文件名的TileSet 类的实例。稍后处理数据的函数使用self.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()