使用tkinter 时的常用方法是使用lambda 函数。棘手的部分是获取返回值,因为command= 函数的返回值被忽略了。人们经常使用global 变量来解决这个问题,但是如果函数是在另一个模块中定义的,那么这种策略将不起作用。幸运的是 tkinter 有几个特定于类型的容器 Variable 子类,它们可以作为参数传递给允许从中检索值的函数。
下面的可运行代码显示了使用它们的一种方法:
script.py
from tkinter import filedialog
def load_file(input_path):
file_name = filedialog.askopenfilename(filetypes=[('EXE files', '*.exe')])
input_path.set(file_name)
def simulation(input_path, input_par): # this works fine
# the function runs an EXE file ang gives me two lists lst1 and lst2
return lst1, lst2
main.py
from script import load_file, simulation
import tkinter as tk
root = tk.Tk()
frame_file = tk.Frame(root)
frame_file.pack()
input_path = tk.StringVar()
input_var = 42
button = tk.Button(frame_file, text='Open file', command=lambda: load_file(input_path))
button.grid(row=1, column=1)
button2 = tk.Button(frame_file, text='Run simulation',
command=lambda: simulation(input_path.get(), input_var))
button2.grid(row=1, column=2)
root.mainloop()
更新
这里有一个稍微复杂但更灵活的版本,它可以处理更多类型的返回值,包括用户定义的类(不仅仅是tkinter 支持的四种——bool、float、int、string)。自动支持更多类型的返回数据,也意味着调用函数不需要修改。
它通过定义一个 CallBack 类来实现这一点,该类的实例“包装”要调用的函数并将它们的返回值保存在 tkinter StringVar 小部件中,以便以后可以通过调用方法 get_result() 来检索它们该类的实例具有。为了处理更多数据类型,它使用 Python 的内置 pickle 模块来临时存储数据。
script2.py
from tkinter import filedialog
def load_file():
file_name = filedialog.askopenfilename(filetypes=[('EXE files', '*.exe')])
return file_name
def simulation(input_path, input_par): # this works fine
# the function runs an EXE file and gives me two lists lst1 and lst2
print(f'simulation({input_path=}, {input_par=}) called')
list1, list2 = ['param', input_par], list('spam')
return list1, list2
main2.py
from script2 import load_file, simulation
import pickle
import tkinter as tk
from tkinter import messagebox
class CallBack:
def __init__(self, func):
self.func = func
self.var = tk.StringVar()
def get_result(self):
pickled_result = self.var.get()
return pickle.loads(pickled_result.encode('latin1')) # Unpickle and return it.
def __call__(self):
res = self.func()
pickled_result = pickle.dumps(res).decode('latin1') # Pickle result.
self.var.set(pickled_result) # And save it in tkinter StringVar.
root = tk.Tk()
frame_file = tk.Frame(root)
frame_file.pack()
input_par = 42
callback1 = CallBack(load_file) # Wrap function from other module.
button = tk.Button(frame_file, text='Open file', command=callback1)
button.grid(row=1, column=1)
def run_sim():
""" Run simulation function and display value returned. """
# Wrap other function in other module to allow results to be retrieved.
callback2 = CallBack(lambda: simulation(callback1.get_result(), input_par))
callback2() # Call the function and save its return value.
results = callback2.get_result() # Get function's return value.
messagebox.showinfo(title='Simulation Results', message=str(results))
button2 = tk.Button(frame_file, text='Run simulation', command=run_sim)
button2.grid(row=1, column=2)
root.mainloop()