如何在关闭tkinter根窗口时保存Canvas矩形的几何参数?
Tkinter窗口关闭时保存Canvas矩形坐标问题解决
问题分析
- 事件多次触发:
<Destroy>事件会在每个组件(根窗口、Canvas、按钮等)被销毁时触发,且事件会向上冒泡到父组件,所以根窗口会收到多次事件回调,导致处理函数被重复调用。 - Canvas存在却无法获取矩形坐标:当根窗口的
<Destroy>事件触发时,Canvas对应的Tcl内部命令已被销毁,winfo_width()依赖的窗口管理器信息尚未清理所以能返回值,但canvas.coords()需要调用Canvas的专属Tcl命令,此时已失效,因此报错。
解决方案
方法1:使用WM_DELETE_WINDOW协议(推荐)
该协议在用户点击窗口关闭按钮时触发,此时窗口未进入销毁流程,所有组件都处于正常状态,可安全获取矩形坐标。
修改后的代码:
import tkinter as tk import json def save_rect_coords(): coords = canvas.coords(box) print("保存矩形坐标:", coords) # 实际项目中可保存到文件,示例: # with open("rect_config.json", "w") as f: # json.dump(coords, f) def on_closing(): save_rect_coords() root.destroy() def print_data(caller): global trial_count trial_count += 1 print(f'---------- trial {trial_count} called from {caller} ------------') print('try canvas.winfo_width()', canvas.winfo_width()) print('try canvas.coords(box)', canvas.coords(box)) def btn(): print_data('button') trial_count = 0 root = tk.Tk() # 绑定窗口关闭协议,替代Destroy事件 root.protocol("WM_DELETE_WINDOW", on_closing) canvas = tk.Canvas(root) canvas.pack() box = canvas.create_rectangle(20, 20, 100, 50) tk.Button(root, text='点击打印', command=btn).pack() # 可选:加载上次保存的坐标 # try: # with open("rect_config.json", "r") as f: # saved_coords = json.load(f) # canvas.coords(box, *saved_coords) # except FileNotFoundError: # pass root.mainloop()
方法2:实时保存矩形坐标
如果需要跟踪矩形的移动/拉伸操作,可在每次修改时就保存坐标,关闭窗口时直接读取已保存的值,无需在关闭事件中临时获取:
import tkinter as tk import json current_coords = [20,20,100,50] def update_coords(event): global current_coords current_coords = canvas.coords(box) # 实时保存到文件 # with open("rect_config.json", "w") as f: # json.dump(current_coords, f) def on_closing(): print("保存的矩形坐标:", current_coords) root.destroy() trial_count = 0 root = tk.Tk() root.protocol("WM_DELETE_WINDOW", on_closing) canvas = tk.Canvas(root) canvas.pack() box = canvas.create_rectangle(*current_coords) # 绑定矩形拖拽/拉伸事件(需自行实现完整拖拽逻辑) canvas.tag_bind(box, '<B1-Motion>', update_coords) tk.Button(root, text='点击打印', command=lambda: print_data('button')).pack() def print_data(caller): global trial_count trial_count += 1 print(f'---------- trial {trial_count} called from {caller} ------------') print('try canvas.winfo_width()', canvas.winfo_width()) print('try canvas.coords(box)', current_coords) root.mainloop()
验证效果
- 点击按钮仍能正常打印Canvas宽度和矩形坐标
- 关闭窗口时仅触发一次保存逻辑,可成功获取并保存矩形坐标,无报错
内容的提问来源于stack exchange,提问作者VanDee
相关产品推荐
相关产品推荐

