4

I am creating a tkinter ttk GUI and I made some radio buttons that select the GUI size. This changes, among other things, the global font size for the whole application.

I made a quick script to demonstrate it.

    import tkinter as tk
    from tkinter import ttk
    import tkinter.font

    UI_SIZES = ["Tiny", "Small", "Normal", "Large", "Huge"]

    TINY_FONT_SIZE = 8
    SMALL_FONT_SIZE = 12
    NORMAL_FONT_SIZE = 16
    LARGE_FONT_SIZE = 18
    HUGE_FONT_SIZE = 22

    root = tk.Tk()

    ui_size = tk.StringVar(root, "Normal")
    entry_text = tk.StringVar(root, "Entry Text")


    def text_size_callback(*_args):
        """change the program font size when the font_size variable changes"""
        font = tkinter.font.nametofont("TkDefaultFont")
        selected_size = ui_size.get()
        if selected_size == "Tiny":
            font.configure(size=TINY_FONT_SIZE)
        elif selected_size == "Small":
            font.configure(size=SMALL_FONT_SIZE)
        elif selected_size == "Normal":
            font.configure(size=NORMAL_FONT_SIZE)
        elif selected_size == "Large":
            font.configure(size=LARGE_FONT_SIZE)
        elif selected_size == "Huge":
            font.configure(size=HUGE_FONT_SIZE)
        root.option_add("*Font", font)


    ui_size.trace('w', text_size_callback)
    ui_size.set("Normal")

    ui_radio_group = ttk.Frame(root)
    ui_size_radios = []
    for sizeval in UI_SIZES:
        ui_size_radios.append(ttk.Radiobutton(
            ui_radio_group,
            text=sizeval,
            variable=ui_size,
            value=sizeval
        ))
    text_entry = ttk.Entry(ui_radio_group, textvariable=entry_text)

    i = 0
    for sizeradio in ui_size_radios:
        sizeradio.grid(row=i, column=0, sticky=tk.W)
        i += 1
    text_entry.grid(row=2, column=1)
    ui_radio_group.pack()

    root.mainloop()

This works well, except for the labels inside entries (and comboboxes). The text itself resizes but the label does not, until the text is edited. This makes the text entries look weird.

Here it is on startup

normal text setting, nothing weird

Then messed up after clicking tiny

text is tiny, but sizing is off

Then fixed after I hit backspace

sizing is fixed after editing text

How can I work around this? Or, how can I do this more correctly so it works without workarounds? I'm on Windows 10, using Python 3.6.3 64-bit, if it helps.

EDIT: I made an example for you all to poke with

DTreth
  • 87
  • 5

1 Answers1

2

After some tests, it seems to happen only with ttk.Entry, not tk.Entry. There are at least two workarounds:

  1. to insert then delete text in the entry after the font size changed
  2. to reconfigure the font of the entry after the font size changed

Here is an example:

import tkinter as tk
from tkinter import ttk
import tkinter.font as tkfont

def change_fontsize():
    font.configure(size=30)

def change_fontsize_1():
    font.configure(size=20)
    # workaround 1
    entry.insert(0, ' ')
    entry.delete(0)

def change_fontsize_2():
    font.configure(size=5)
    # workaround 2
    entry.configure(font=font)


root = tk.Tk()

font = tkfont.Font(root)
entry = ttk.Entry(root, font=font)
entry.insert(0, 'Entry Text')
entry.pack()

ttk.Button(root, text='Change size, no workaround', command=change_fontsize).pack()
ttk.Button(root, text='Change size, workaround 1', command=change_fontsize_1).pack()
ttk.Button(root, text='Change size, workaround 2', command=change_fontsize_2).pack()

root.mainloop()
j_4321
  • 15,431
  • 3
  • 34
  • 61
  • This is a pretty brilliant answer, but it requires my text setter to know about every entry widget I need to "correct". Is there an event I can catch in the entry itself that would allow me to reset the font attribute? – DTreth Nov 22 '17 at 16:34
  • Also, is this a ttk bug that i should be filing somewhere? – DTreth Nov 22 '17 at 16:38
  • @DTreth I think it is a ttk bug and I have just checked that the same problem occurs with a tcl script instead of python. It is worth filling a bug report if it has not already been reported. About the first comment, since it is the font object which is modified, I doubt that any kind of event can be used to reconfigure the entries. The only solution I see for now is to have a list of all entries sharing the same font and reconfiguring all of them iteratively when the font size is changed. – j_4321 Nov 22 '17 at 21:33