You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

tk.Toplevel选日期后关窗触发_tkinter.TclError错误求助

问题:Tkinter日期选择窗口关闭时触发_tkinter.TclError错误

我编写了一个tk.Toplevel类用于获取用户选择的日期。用户点击日期后,窗口关闭并将日期返回至主程序。虽然能成功获取日期,但窗口关闭时会触发错误:_tkinter.TclError: bad window path name ".!kalender.!dateentry.!toplevel"。

代码如下:

class Kalender(tk.Toplevel):
    def __init__(self, parent, date=''):
        Toplevel.__init__(self, parent)

        # Fenster mittig zentrieren
        x = (self.winfo_screenwidth() // 2) - (100 // 2)
        y = (self.winfo_screenheight() // 2) - (50 // 2)
        self.grab_set()
        self.geometry('{}x{}+{}+{}'.format(180, 90, x, y))
        self.attributes('-toolwindow', True)
        self.title('Datum auswählen')
        self.resizable(width=False, height=False) 

        self.date = None
        self.sel = StringVar()
        self.cal = DateEntry(self, font="Arial 14", selectmode='day', locale='de_DE', date_pattern="dd.mm.y ",
                             textvariable=self.sel)
        self.cal.bind("<<DateEntrySelected>>", self.close_window)
        self.cal.set_date(date)
        self.cal.grid(row=0, column=0, padx=10, pady=10, sticky=W+E)
        self.focus_set()


    def close_window(self, e):
        self.date = self.cal.get()
        self.destroy()

    def show(self):
        self.deiconify()
        self.wm_protocol("WM_DELETE_WINDOW", self.close_window)
        self.wait_window()
        return self.date
cal = Kalender(main_window, d).show()

报错信息:

Exception in Tkinter callback
Traceback (most recent call last):
  File "B:\Python 310\lib\tkinter\__init__.py", line 1921, in __call__
    return self.func(*args)
  File "B:\Python 310\lib\site-packages\tkcalendar\dateentry.py", line 301, in _select
    self._top_cal.withdraw()
  File "B:\Python 310\lib\tkinter\__init__.py", line 2269, in wm_withdraw
    return self.tk.call('wm', 'withdraw', self._w)
_tkinter.TclError: bad window path name ".!kalender.!dateentry.!toplevel"

我猜测问题出在Tkinter尝试调用已被销毁的kalender.dateentry组件。请问我哪里出错了?


解决方案

错误原因

当你选择日期触发<<DateEntrySelected>>事件时,close_window方法直接销毁了整个Toplevel窗口。但tkcalendar的DateEntry组件在用户选择日期后,内部还会执行self._top_cal.withdraw()来隐藏它弹出的日历窗口——此时主窗口已经被销毁,DateEntry组件也跟着被回收,导致找不到对应的窗口路径,从而抛出错误。

另外,窗口关闭按钮绑定的close_window方法需要事件参数,但点击叉号关闭时不会传递参数,还会触发另一个参数不匹配的错误(只是当前被TclError掩盖了)。

修改后的代码

import tkinter as tk
from tkcalendar import DateEntry

class Kalender(tk.Toplevel):
    def __init__(self, parent, date=''):
        super().__init__(parent)  # 使用super()调用父类构造,更规范

        # 窗口居中修正(原计算数值与窗口尺寸不匹配)
        win_width, win_height = 180, 90
        x = (self.winfo_screenwidth() // 2) - (win_width // 2)
        y = (self.winfo_screenheight() // 2) - (win_height // 2)
        self.grab_set()
        self.geometry(f'{win_width}x{win_height}+{x}+{y}')
        self.attributes('-toolwindow', True)
        self.title('选择日期')
        self.resizable(width=False, height=False) 

        self.date = None
        self.sel = tk.StringVar()
        self.cal = DateEntry(self, font="Arial 14", selectmode='day', locale='de_DE', 
                             date_pattern="dd.mm.y ", textvariable=self.sel)
        self.cal.bind("<<DateEntrySelected>>", self.on_date_selected)
        self.cal.set_date(date)
        self.cal.grid(row=0, column=0, padx=10, pady=10, sticky=tk.W+tk.E)
        self.focus_set()

    def on_date_selected(self, e):
        self.date = self.cal.get()
        # 延迟10ms销毁窗口,给DateEntry足够时间完成内部操作
        self.after(10, self.destroy_window)

    def destroy_window(self):
        # 无参的销毁方法,适配窗口关闭按钮的绑定
        self.destroy()

    def show(self):
        self.deiconify()
        self.wm_protocol("WM_DELETE_WINDOW", self.destroy_window)
        self.wait_window()
        return self.date

# 调用示例
# main_window = tk.Tk()
# d = "01.01.2024"
# cal = Kalender(main_window, d).show()
# main_window.mainloop()

关键修改点

  1. 拆分日期选择与窗口销毁逻辑:将原close_window拆分为on_date_selected(处理日期获取)和destroy_window(负责窗口销毁),避免在事件回调中直接销毁窗口。
  2. 延迟销毁窗口:使用self.after(10, self.destroy_window)让DateEntry有足够时间完成隐藏内部日历窗口的操作,再销毁主窗口。
  3. 修复窗口关闭按钮绑定:绑定无参的destroy_window方法,避免点击叉号时的参数不匹配错误。
  4. 修正窗口居中计算:原代码中居中计算的数值与窗口实际尺寸不符,调整后实现真正的居中显示。

内容的提问来源于stack exchange,提问作者Benaja

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 20:30:37