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

使用sv_ttk库为多个Tkinter窗口设置主题时触发_Tkinter.TclError错误

sv_ttk库为多个Tkinter窗口设置主题时触发_Tkinter.TclError错误

我完全明白你遇到的困扰——单独给主设置窗口或者兵升变弹窗用sv_ttk暗色主题都没问题,但同时给两个窗口设置就会弹出_tkinter.TclError: can't invoke "winfo" command: application has been destroyed的错误,这确实挺让人头疼的。咱们来拆解问题根源,再给出对应的解决办法。

问题根源

首先得搞清楚sv_ttk的主题设置逻辑:sv_ttk.use_dark_theme()本质是调用set_theme("dark"),而这个set_theme函数默认会用tkinter._get_default_root()获取第一个创建的Tk根窗口作为操作对象。

当你创建第二个Tk()实例(也就是那个兵升变弹窗),然后调用use_dark_theme()时,它依然会尝试去操作第一个根窗口(主设置窗口)。如果此时主窗口已经被关闭销毁,或者两个独立的Tcl解释器实例(每个Tk()对应一个)发生冲突,就会触发这个“应用已销毁”的错误。

另外还要提一句:Tkinter本身就不推荐创建多个Tk()实例,因为每个实例对应独立的Tcl解释器,很容易引发主题、资源共享这类奇怪的问题。

解决方案

这里给你两个方案,优先推荐第一个,更符合Tkinter的设计规范:

方案1:把弹窗改成Toplevel(最推荐)

把弹窗从独立的Tk()改成主窗口的Toplevel子窗口,这样所有窗口共享同一个Tcl解释器,主题只需设置一次就会自动应用到所有子窗口,不需要重复调用sv_ttk的主题函数。

修改后的弹窗代码大概是这样:

def askPawnPromotion(main_root):  # 传入主窗口的实例
    """
    Ask the player which piece to promote the pawn to.
    This function uses a Tkinter window to prompt the player for a piece to promote the pawn to.
    """
    def apply_selection():
        global PROMOTION_PIECE
        PROMOTION_PIECE = promotion_combo.get()
        popup.destroy()

    global PROMOTION_PIECE
    # 用Toplevel代替Tk(),绑定到主窗口
    popup = t.Toplevel(main_root)
    ntkutils.dark_title_bar(popup)
    popup.title("Good Chess | Pawn Promotion")
    popup.iconbitmap("images/GAME/icon.ico")
    window_width = 350
    window_height = 200
    screen_width = popup.winfo_screenwidth()
    screen_height = popup.winfo_screenheight()
    x_position = (screen_width - window_width) // 2
    y_position = (screen_height - window_height) // 2
    popup.geometry(f"{window_width}x{window_height}+{x_position}+{y_position}")

    promotion_label = ttk.Label(popup, text="Choose a piece to promote the pawn to:")
    promotion_combo = ttk.Combobox(popup, values=["Queen", "Rook", "Bishop", "Knight"])
    promotion_combo.set("Queen")
    apply_button = ttk.Button(popup, text="APPLY", command=apply_selection)

    promotion_label.pack(pady=10)
    promotion_combo.pack(pady=10)
    apply_button.pack(pady=20)

    # 这里不需要再调用sv_ttk的主题函数,会自动继承主窗口的主题
    popup.mainloop()
    return PROMOTION_PIECE[0]

然后主窗口里只需要调用一次sv_ttk.use_dark_theme()就够了,弹窗会自动用上这个主题。

方案2:强制指定主题应用的窗口(适合必须保留多Tk实例的场景)

如果因为某些特殊原因,你必须保留两个独立的Tk()实例,那可以在调用主题设置时,明确指定要应用的窗口实例,而不是依赖默认的根窗口:

  • 主窗口里把sv_ttk.use_dark_theme()改成:
sv_ttk.set_theme("dark", root=root)
  • 弹窗里把sv_ttk.use_dark_theme()改成:
sv_ttk.set_theme("dark", root=popup)

这样sv_ttk就会分别对指定的窗口应用主题,不会再去操作另一个窗口的资源。

额外提示

尽量避免创建多个Tk()实例,除了主题问题,还可能导致事件循环异常、资源无法共享等一系列潜在问题。如果主窗口关闭后弹窗还需要运行,用Toplevel的话可以修改主窗口的关闭协议(比如隐藏窗口而不是销毁),或者调整你的应用窗口层级结构。

备注:内容来源于stack exchange,提问作者Rares Olteanu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.20 11:14:36