Python Tkinter里取回button 回调函数的变量

这篇博客介绍了在Python Tkinter中如何从Button的回调函数中获取变量值。作者通过示例代码展示了在点击Button后如何正确获取并保存文件路径,讨论了mainloop的工作原理以及组件销毁的影响。最后强调了理解变量绑定和组件生命周期的重要性。

Python Tkinter里取回button 回调函数的变量

最近在尝试用用python的内置库tkinter写一个GUI应用,碰到了一些问题,这里note一下。
开发工具:pycharm
库:Tkinter
python 版本: python3.6

Button 组件介绍

buttonTkinter里实现的是一个按钮功能。但是这里想实现取出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组件被关闭了,只要在组件被关闭之前取到了组件或子组件的相关变量,它就可以在内存中保存下来。从而在组件被关闭的情况下继续被使用。

总结

关于在tkinterbutton组件的变量获取关键是理解destory()mainloop()的作用机制,再就是要知道
哪些获取变量的方法。

在tkinter模块库中,绑定在组件上的变量是变量类的实例,这些类是StringVar, Intvar,DoubleVar;具体要使用哪一个类要根据具体情况而定。比如,StringVar类的实例可以与一个Entry框相关。关于这一块大家可以参考《Python 编程》一书,里面对tkinter有一个很系统的讲解,虽然很多专有名字我也听不懂,但是搭配着《python学习手册》还有网上的各种资料,还是可以慢慢看懂的。

我是一只想做程序猿的通信汪!

<think>好的,我现在需要回答用户关于TkinterButton的操作函数是否可以嵌套的问题。首先,我得回忆一下自己之前学过的Tkinter知识。记得在Tkinter中,按钮的command参数通常指定一个函数,当按钮被点击时就会调用这个函数。那用户的问题是关于这些操作函数是否可以嵌套,也就是在一个按钮的回调函数再创建另一个按钮或者触发其他按钮的功能。 首先,我应该确定“嵌套”具体指什么。用户可能是指在一个按钮的回调函数中定义另一个按钮,或者在一个回调函数调用其他函数,包括可能创建新的按钮实例。这时候,我需要举例子来说明两种情况。 比如,假设有一个按钮A,当点击它时,会动态创建另一个按钮B。这种情况是否可行?根据Tkinter的工作原理,主循环是在mainloop()中运行的,而回调函数是在事件循环中被调用的,所以在回调函数中创建新控件是允许的,只要在主窗口销毁之前。这时候,应该可以动态添加按钮,所以嵌套创建是可能的。 另一个情况是,按钮的回调函数是否可以调用其他函数,包括其他按钮的回调函数。例如,按钮A的回调函数内部调用按钮B的invoke()方法,从而触发按钮B的功能。这种情况下,函数之间的调用是没问题的,只要逻辑正确,不会有问题。 接下来,我需要验证这些情况是否正确。比如,写一个简单的示例代码,在按钮A的回调函数创建按钮B,并添加到窗口中。然后测试是否能正常工作。同时,另一个示例是按钮A触发时调用按钮B的invoke方法,看看是否能触发按钮B的功能。 然后,可能需要注意的问题,比如在回调函数中频繁创建新控件可能导致内存问题,或者界面布局混乱。此外,无限递归的情况,比如按钮A触发按钮B,按钮B又触发按钮A,可能导致栈溢出,需要提醒用户避免这种情况。 总结起来,答案应该是肯定的,可以嵌套,但需要注意事项。然后给出具体的例子,比如动态创建按钮,或者函数间调用,并说明可能的问题。</think>在Tkinter中,Button的操作函数(即`command`参数绑定的回调函数)**完全可以嵌套调用或动态创建其他控件**。以下是具体说明和示例: --- ### 一、嵌套调用的两种形式 #### 1. 回调函数内创建新按钮 ✅ ```python import tkinter as tk def create_new_button(): # 在回调函数内部动态创建另一个按钮 btn2 = tk.Button(root, text="新按钮", command=lambda: print("新按钮被点击")) btn2.pack() root = tk.Tk() btn1 = tk.Button(root, text="点击我生成新按钮", command=create_new_button) btn1.pack() root.mainloop() ``` - **现象**:点击第一个按钮后,会动态生成第二个按钮。 - **原理**:Tkinter的事件循环(`mainloop()`)允许在回调函数中修改GUI组件,包括动态创建控件。 --- #### 2. 回调函数内触发其他按钮 ✅ ```python import tkinter as tk def action1(): print("执行操作1") # 直接调用另一个按钮的回调函数 btn2.invoke() def action2(): print("执行操作2") root = tk.Tk() btn1 = tk.Button(root, text="按钮1", command=action1) btn2 = tk.Button(root, text="按钮2", command=action2) btn1.pack() btn2.pack() root.mainloop() ``` - **现象**:点击按钮1会依次输出`执行操作1`和`执行操作2`。 - **原理**:通过`btn.invoke()`方法可以主动触发按钮的`command`函数。 --- ### 二、注意事项 1. **递归风险** 如果按钮A的回调触发按钮B,按钮B又触发按钮A,会导致无限递归: ```python def action_a(): btn_b.invoke() # 危险操作! def action_b(): btn_a.invoke() # 形成死循环 ``` 2. **内存管理** 动态创建大量控件时,需及时销毁旧对象(使用`.destroy()`),避免内存泄漏: ```python def create_button(): global temp_btn if 'temp_btn' in globals(): temp_btn.destroy() # 销毁旧按钮 temp_btn = tk.Button(...) ``` 3. **线程安全** 在回调函数中避免直接操作主线程外的GUI组件,如需复杂计算,应使用多线程。 --- ### 三、完整示例:嵌套按钮与函数调用 ```python import tkinter as tk def outer_function(): print("外层函数被调用") def inner_function(): print("内层函数被调用") # 动态创建嵌套按钮 inner_btn = tk.Button(root, text="内层按钮", command=inner_function) inner_btn.pack() root = tk.Tk() main_btn = tk.Button(root, text="外层按钮", command=outer_function) main_btn.pack() root.mainloop() ``` - **效果**:点击外层按钮会打印信息,并生成一个可触发内层函数的新按钮。 --- ### 结论 Tkinter允许在按钮回调函数中嵌套调用其他函数或动态创建控件,但需注意**递归风险**和**资源管理**。合理利用此特性可以实现动态交互界面。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值