How to set a Tkinter widget to a monospaced, platform independent font?
Asked Answered
K

1

15

It's said here in the section Standard Fonts:

Particularly for more-or-less standard user interface elements, each platform defines specific fonts that should be used. Tk encapsulates many of these into a standard set of fonts that are always available, and of course the standard widgets use these fonts. This helps abstract away platform differences.

And then in the predefined fonts list there is:

TkFixedFont A standard fixed-width font.

This also corresponds with what I could find here on the standard ways of choosing a monospaced, platform independent font in Tkinter like for example stated in this answer.

Alas, when I try to do this on my own, like with the simple code below:

import tkinter as tk
from tkinter import ttk

root = tk.Tk()
frame = ttk.Frame(root)
style = ttk.Style()
style.configure("Fixed.TButton", font=("TkFixedFont", 16))

button = ttk.Button(text="Some monospaced text, hopefully", style="Fixed.TButton")
frame.grid()
button.grid(sticky="news")
button.configure(text="I don't quite like this font.")

what I get is this:

TkFixedFont, size 16

That doesn't look like monospaced to me, so I check what exactly Tkinter translates TkFixedFont into on my platform with:

from tkinter import font
font.nametofont("TkFixedFont").actual()

and the answer is:

{'family': 'DejaVu Sans Mono', 'size': 9, 'weight': 'normal', 'slant': 'roman', 'underline': 0, 'overstrike': 0}

So how does DejaVu Sans Mono look like?

DejaVu Sans Mono, size 16

The Tkdocs.com tutorial quoted above has also a section on Named Fonts and there it says:

the names Courier, Times, and Helvetica are guaranteed to be supported (and mapped to an appropriate monospaced, serif, or sans-serif font)

So I try with:

style.configure("Courier.TButton", font=("Courier", 16))
button.configure(style="Courier.TButton")

and now finally I get a monospaced result:

enter image description here

Admittedly, it's Courier New and not DejaVu Sans Mono that my platform chooses as the standard monospaced font, but that's at least something, right? But shouldn't TkFixedFont just work?

Knuth answered 11/2, 2018 at 13:1 Comment(0)
D
17

Standard fonts (including TkFixedFont) can only be given as a plain string, not as a tuple. I.e. font='TkFixedFont' works, while font=('TkFixedFont',) (note the parentheses and comma) will not.

This seems to be the general case. I tried it with both Tkinter.Button and ttk.Style.

For styles that means:

import Tkinter
import ttk

# will use the default (non-monospaced) font
broken = ttk.Style()
broken.configure('Broken.TButton', font=('TkFixedFont', 16))

# will work but use Courier or something resembling it
courier = ttk.Style()
courier.configure('Courier.TButton', font=('Courier', 16))

# will work nicely and use the system default monospace font
fixed = ttk.Style()
fixed.configure('Fixed.TButton', font='TkFixedFont')

Tested to work with Python 2.7 on both Linux and Windows [Edit: and it's still true as of today on Python 3.x]

Bottom line is that the code in the question will work perfectly fine if just the parentheses around "TkFixedFont" were removed.

Dermis answered 4/7, 2018 at 21:21 Comment(3)
I'm not as well versed in TkInter intricacies now as I used to be this 4 months ago but a quick look here confirmed my worry you're talking about tkinter.Button (which can be initialized with font option) and I asked about tkinter.tkk.Button which doesn't have it. Probably I should've made it more clear in the title that the question was about ttk widgetsKnuth
wondering how to use Fixed.Button and specify the size?Clinkerbuilt
@Clinkerbuilt You should post a new question, referencing this answer in the body via hyperlink. PS I've been "tinkering" with tkinter for a year and with more learning from answers like above, it just keeps getting better :)Mozza

© 2022 - 2024 — McMap. All rights reserved.