Python Tkinter里取回button 回调函数的变量
最近在尝试用用python的内置库tkinter写一个GUI应用,碰到了一些问题,这里note一下。
开发工具:pycharm
库:Tkinter
python 版本: python3.6
Button 组件介绍
button在 Tkinter里实现的是一个按钮功能。但是这里想实现取出command=func 中回调函数的变量值,因为在点击button后
回调函数才开始被调用,但是语句self.button = Button(command = func) 执行后self.button 接收的是.!application.!button,即使在
get_file_path实例方法内添加return self.file_name , 结果还是一样的,而且这个结果是在程序Run后不需要点击button就打印了
,即button创建的时候就打印了。
Tips: 如果把command = func 改成command = print('hello world') , 即把command=后的函数名直接写成语句,那么button不需要点击就会在创建的时候执行这个语句,所以一般可以在语句前加上 匿名函数lambda , 这里是lambda: print('Hello world'), Button就会在点击后才打印Hello World, 匿名函数实现了延迟调用的效果,这里具体怎么实现的还有待考究,如果知道的大神可以帮忙分析一波。
代码分析
先看一下代码
from tkinter import *
from tkinter.filedialog import askopenfilename
class Application(Frame):
def __init__(self, parent=None): #这里重写Application的父容器Frame,从而让其成为顶级容器
Frame.__init__(self, parent) #父容器Frame的parent是TK(),这个是所tkinter的组件的主窗口
self.pack(expand=YES) #打包application, tkinter会自动为其画一个矩形框,其所有的子部件将在这个矩形框里布局
#如果没有这个pack(),所有继承self的子类将都不会出现在主窗口中,表现形式上就是主窗口是个空的。
self.create_widget()
def create_widget(self): #创建组件
self.lab = Label(self, text='File_Path').grid(row=0, column=0)
self.ent = Entry(self, width=40)
self.ent.grid(row=0,column=1)
self.button = Button(self, text='Open', command=self.get_file_path).grid(row=0, column=2)
self.button = Button(self, text='submit', command=self.submit).grid(row=1,column=0)
def get_file_path(self): #获取文件路径
self.ent.delete(0, END) #先清空文件名框内的内容
self.file_name = askopenfilename(filetypes=[('All Files', '.zip'),('All Files','.csv')) #弹出文件复选框,选择文件,可以指定文件类型以过滤
self.ent.insert(END, self.file_name) #显示文件名,用insert方法把文件名添加进去
def submit(self): #点击提交的时候获取button内回调函数的变量值,这里是文件路径
self.file_path = self.ent.get() #用组件Entry的get获取输入框内的字符串,其在组件被销毁前就被取到
self.destory() #中断循环,即主程序跳出无限循环mainloop(),但是这里是销毁的Frame组件,因为self指的是Frame的派生
#root.destroy() #同样是跳出mainloop(),但是这里销毁的是主窗口Tk(),默认情况下它是所有tkinter 组件的父容器
#root = Tk() #将主窗口实例化
app = Application() #将application实例化
app.mainloop()
print(app.file_path) #打印组件button 回调函数的变量
程序运行后会出现如下所示的GUI界面, 这是个获取文件全路径的GUI

点击open后就会弹出文件复选框,

但选择文件后,文件名会出现在file_path路径后

点击submit, 会出现一个有趣的现象,Frame内的内容不见了,因为程序执行了self.destory() 后这里的Frame就被销毁了,但是主窗口还在,同时我们发现命令行还没有打印出app.file_path的变量值。

为什么呢,思考一下,三秒钟。1,2,3
好,继续往下看, 你应该发现了
因为mainloop函数还在执行啊,mainloop还在无限循环中,也就是说上述的代码其实一直在app.mainloop()中,并没有退出来
app.mainloop() #在这里循环,等待消息
那么这样才会结束这个循环跳出来执行循环外的语句体呢? 必须等被主窗口关掉,循环才会结束。
tkinter内所有的组件都是以类的继承来实现组件上的层级结构的,也就是说刚才被销毁的Frame就是上面这个主窗口的二级组件,它的活动范围也将被限定在这个主窗口内。
既然必须关闭主窗口,那我们直接点击这个空白窗口右上角的X就行了, 点击关闭后,发现命令行打印出了文件路径,也就是说
程序执行了最后一行语句print(app.file_path) 。

如果我们代码作如下修改, 在submit内注释掉对Frame的销毁,换成对root的销毁,同时这里需要在主程序中去掉root = Tk()的注释。
def submit(self):
... ...
#self.destroy()
root.destroy()
root = Tk()
再运行一下程序,我们发现点击submit后,主窗口直接关闭了,同时命令行打印出了文件路径的信息。 这正符合我们的预期,
因为root就是主窗口Tk()的实例,我们在实例方法submit里销毁的是主窗口。组件在被销毁前,我们就已经取到了变量值。
当然,如果在组件被销毁之后取值也就会失败。这里取的值是从组件Entry里得来的,Entry在这个应用里的层级结构是三级组件。因为Entry被实例化的时候指定了其
父容器为self,即Application类,所以当实例app被销毁后,其子类的实例也会一起被销毁,即组件被销毁后,其所有子类的组件都被被销毁。
这里再思考一个问题,为什么实例app 被销毁了,我们还可以打印出它的属性值呢。
这里不要误会了,我的理解是此销毁非内存销毁,而是GUI组件被关闭了,只要在组件被关闭之前取到了组件或子组件的相关变量,它就可以在内存中保存下来。从而在组件被关闭的情况下继续被使用。
总结
关于在tkinter 里button组件的变量获取关键是理解destory()对mainloop()的作用机制,再就是要知道
哪些获取变量的方法。
在tkinter模块库中,绑定在组件上的变量是变量类的实例,这些类是StringVar, Intvar,DoubleVar;具体要使用哪一个类要根据具体情况而定。比如,StringVar类的实例可以与一个Entry框相关。关于这一块大家可以参考《Python 编程》一书,里面对tkinter有一个很系统的讲解,虽然很多专有名字我也听不懂,但是搭配着《python学习手册》还有网上的各种资料,还是可以慢慢看懂的。
我是一只想做程序猿的通信汪!
这篇博客介绍了在Python Tkinter中如何从Button的回调函数中获取变量值。作者通过示例代码展示了在点击Button后如何正确获取并保存文件路径,讨论了mainloop的工作原理以及组件销毁的影响。最后强调了理解变量绑定和组件生命周期的重要性。
4251





