Python Tkinter关闭子窗口后重新启用主窗口按钮失效问题
问题排查结果
回调未触发是三个代码错误共同导致的:
- 窗口关闭协议名拼写错误:代码中写的
"WN_DELET_WINDOW"存在两处错误,正确协议名为"WM_DELETE_WINDOW"——首段标识是WM不是WN,DELETE单词漏写了字母E,协议名不匹配会直接导致绑定失效。 - 回调函数参数定义错误:
protocol()绑定的回调由Tkinter事件循环自动触发,不会主动传入lock参数,当前on_closing方法定义了额外的必传形参,即便协议名正确,触发时也会抛出参数不匹配的运行错误。 - 子窗口创建逻辑错误:Tkinter程序全局只能有一个
Tk()根窗口实例,其余子窗口、弹窗必须用Toplevel()创建。当前代码在子窗口类中新建了独立的Tk()实例,会生成两套独立的事件循环,直接导致事件绑定响应异常。
修复后代码
from tkinter import Toplevel, Label, NORMAL class SerialTkWindow(): def __init__(self, lock) -> None: # 存主窗口按钮实例为类属性,供回调直接调用 self.target_btn = lock # 子窗口唤起时立即禁用触发按钮 self.target_btn.configure(state='disable') # 子窗口使用Toplevel创建,依附主窗口事件循环 self.sub_win = Toplevel() self.sub_win.geometry('300x100') self.sub_win.title("Reset HU ?") self.sub_win.resizable(0,0) welcomeLbl = Label(self.sub_win,text="Select COM Port",fg="black",bg=self.sub_win["bg"],font="Helvetica 12") welcomeLbl.pack() # 绑定修正后的窗口关闭协议 self.sub_win.protocol("WM_DELETE_WINDOW", self.on_closing) def on_closing(self): print("Regresamos") # 恢复主窗口按钮状态 self.target_btn.configure(state=NORMAL) # 销毁子窗口 self.sub_win.destroy()
主窗口调用逻辑不需要额外修改,点击按钮时正常实例化类即可,示例:
# 主窗口按钮点击事件 def CANMsgBtn(self): # 直接传入按钮实例即可,不需要额外调用mainloop SerialTkWindow(self.sendCanBtn)
注意事项
- 禁止在单个Tkinter程序中创建多个
Tk()实例,否则会出现事件响应失效、控件状态不同步等无明确报错的异常问题。 - 如果不想导入Tkinter的状态常量,按钮状态可以直接用小写字符串
'normal'、'disabled'设置,兼容性更好。 protocol()绑定的回调如果需要传参,优先通过类实例属性传递,或用lambda闭包包装,不要直接给回调方法加必传形参。
内容的提问来源于stack exchange,提问作者Jorge A. Garcia-Hernandez
相关产品推荐
相关产品推荐

