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?
Output. Running the above code will set the default font as "lucida 20 bold italic" for all the widgets that uses textual information.
A font can be specified as tuple containing a family name, a height in points, and optionally a string with one or more styles. To get the default size and style, you can give the font name as a single string.
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:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With