Tkinter多窗口跳转时子窗口Form2自定义字体不生效无报错如何解决
问题根因
- Tkinter不支持多
tk.Tk()实例的资源共享:每个tk.Tk()实例对应独立的Tcl解释器运行上下文,自定义字体、图片等资源默认绑定到创建资源时活跃的tk.Tk实例,无法跨实例生效。单独运行Form2时整个进程只有一个tk.Tk实例,字体可以正常识别;通过Form1触发打开Form2时,Form2作为第二个tk.Tk实例,其内部创建的字体资源默认绑定到已存在的Form1实例上下文,Form2自身的上下文无法识别该字体,就会静默降级为系统默认字体,不会抛出报错。 - 重复调用
mainloop()不符合规范:一个Tkinter应用全局只需要执行一次mainloop()处理全局事件,在按钮点击事件里第二次调用mainloop()也会引发资源加载、事件处理的异常。
修复方案
核心修改逻辑是将子窗口Form2的继承对象从tk.Tk改为专门用于子窗口的tk.Toplevel类,Toplevel会共享主窗口的Tcl上下文,资源可以通用,同时移除多余的mainloop()调用。
修改后的可运行代码如下:
from tkinter.ttk import * import tkinter as tk from tkinter import messagebox from tkinter import * import tkinter.font as tkFont # 改为继承tk.Toplevel而非tk.Tk class Form2(tk.Toplevel): def __init__(self): super().__init__() self.title("Form2") self.geometry("350x600") self.resizable(0, 0) self.label = tk.Label(self, text='form2', font=tkFont.Font(family="Roboto", size=18)) self.label.pack() class Form1(tk.Tk): def __init__(self): super().__init__() self.title("Form1") self.geometry("350x600") self.resizable(0, 0) self.label = tk.Label(self, text='form1', font=tkFont.Font(family="Roboto", size=18)) self.label.pack() self.button: object = tk.Button(self, overrelief="solid", width=10, height=2, repeatdelay=1000, repeatinterval=100, text="Preferences", font=tkFont.Font(family="Roboto", size=9), command=lambda: self.button_clicked()) self.button.pack() def button_clicked(self): # 直接创建Form2实例即可,不需要调用mainloop form2 = Form2() if __name__ == '__main__': form1 = Form1() form1.mainloop()
补充说明
如果确实有特殊场景需要使用多tk.Tk()实例,可以在创建字体时显式指定字体绑定的master为当前窗口,例如Form2中创建字体的代码改为tkFont.Font(self, family="Roboto", size=18),手动绑定到Form2实例即可生效,但这种方案仍然不推荐,多Tk实例会引发很多隐性问题,优先使用Toplevel实现多窗口需求。
内容的提问来源于stack exchange,提问作者freshcodeman
相关产品推荐
相关产品推荐

