Defining a font inside a function and in the main body of the script seems to behave differently, and I can't seem to figure out how it's supposed to work.
For example, the Label
in this example ends up being in a larger font, as expected:
from Tkinter import *
from ttk import *
import tkFont
root = Tk()
default = tkFont.Font(root=root, name="TkTextFont", exists=True)
large = default.copy()
large.config(size=36)
style = Style(root)
style.configure("Large.TLabel", font=large)
root.title("Font Test")
main_frame = Frame(root)
Label(main_frame, text="Large Font", style="Large.TLabel").pack()
main_frame.pack()
root.mainloop()
However, if I try to define styles inside a function, it seems like the font gets deleted or garbage collected and is not available by the time the widget needs to use it:
from Tkinter import *
from ttk import *
import tkFont
def define_styles(root):
default = tkFont.Font(root=root, name="TkTextFont", exists=True)
large = default.copy()
large.config(size=36)
style = Style(root)
style.configure("Large.TLabel", font=large)
root = Tk()
root.title("Font Test")
define_styles(root)
main_frame = Frame(root)
Label(main_frame, text="Large Font", style="Large.TLabel").grid(row=0, column=0)
main_frame.pack()
root.mainloop()
Printing out tkFont.names()
in the first version just before the main_frame.pack()
lists the custom font as font<id>
, but printing the same in the second version does not list the custom font outside the define_styles
function. Do I have to do something special to save them?
Why can't I put that code in a function? Am I fundamentally misunderstanding something about how Fonts are supposed to be used? tkFont
seems to have some kind of font registry, why aren't mine sticking around?
I have no evidence to back this up, but I believe that your large
Font object is being garbage collected by Python once define_styles
ends. This is because no pure Python objects have any references to it, even though the underlying Tcl implementation is still using it. This is a problem that afflicts Tkinter's PhotoImage
class, as well.
The workaround is to keep the object alive by making a long-lived reference to it. Just assign it to any old attribute on the root
object, for example.
def define_styles(root):
default = tkFont.Font(root=root, name="TkTextFont", exists=True)
large = default.copy()
large.config(size=36)
style = Style(root)
style.configure("Large.TLabel", font=large)
root.myfont = large
Result: