Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you Make Python Tkinter Text Automatically Resize in Buttons and Labels?

I have encountered a problem while coding in Python that I cannot find a solution to. I have a tkinter grid that automatically resizes to fit the size of window it is in, but I want the text within the buttons/labels to also resize to fit the new grid. A basic example of this is below:

from tkinter import *

root = Tk()

for x in range(3):
    for y in range(3):
        Label(root, width = 2, height = 4, text = (y * 3 + x) + 1, relief = GROOVE).grid(row = y, column = x, sticky = N+E+S+W)
        Grid.rowconfigure(root, y, weight = 1)
        Grid.columnconfigure(root, x, weight = 1)

root.mainloop()

I would like the text to increase as you drag the window to expand it. How can this be done?


EDIT:

Mike - SMT's solution works well, however not with the situation I described in the comment on his reply.

Here is the code I have:

from tkinter import *
import tkinter.font as tkFont

grey = [0,1,2,6,7,8,9,10,11,15,16,17,18,19,20,24,25,26,30,31,32,39,40,41,48,49,50,54,55,56,60,61,62,63,64,65,69,70,71,72,73,74,78,79,80]
btn_list = []

filled = []
filled_ID = []

class GUI(Frame):
    def __init__(self, master = None):
        Frame.__init__(self, master)

        self.screen_init()

        self.key = None
        self.keydetection = False
        self.detect()
        self.bind_all("<Key>", self.key_event)

    def screen_init(self, master = None):
        for x in range(9):
            for y in range(9):
                btn_list.append(Button(master, width = 40, height = 40, image = pixel, compound = CENTER, bg = "#D3D3D3" if 9 * y + x in grey else "#FFFFFF", command = lambda c = 9 * y + x: self.click(c)))
                btn_list[-1].grid(row = y, column = x, sticky = N+E+S+W)
                Grid.rowconfigure(root, y, weight = 1)
                Grid.columnconfigure(root, x, weight = 1)

    def update(self, btn_ID, number = None, colour = "#000000", master = None):
            y = btn_ID // 9
            x = btn_ID % 9
            Button(master, width = 40, height = 40, image = pixel, text = number, compound = CENTER, fg = colour, bg = "#D3D3D3" if 9 * y + x in grey else "#FFFFFF", command = lambda c = 9 * y + x: self.click(c)).grid(row = y, column = x, sticky = N+E+S+W)

    def detect(self):
        self.keydetection = not self.keydetection

    def key_event(self, event):
        try:
            self.key = int(event.keysym)
        except:
            print("Numbers Only!")

    def click(self, btn_ID):
        if btn_ID in filled:
            filled_ID.pop(filled.index(btn_ID))
            filled.remove(btn_ID)
            window.update(btn_ID)
        else:
            filled.append(btn_ID)
            filled_ID.append(self.key)
            window.update(btn_ID, self.key)

def font_resize(event=None):
    for btn in btn_list:
        x = btn.winfo_width()
        y = btn.winfo_height()
        if x < y:
            btn.config(font=("Courier", (x-10)))
        else:
            btn.config(font=("Courier", (y-10)))

if __name__ == '__main__':
    root = Tk()
    root.title("Example")
    pixel = PhotoImage(width = 1, height = 1)
    font = tkFont.Font(family = "Helvetica")
    window = GUI(root)
    root.bind("<Configure>", font_resize)
    root.mainloop()

This means that the text is not in the grid when the code is originally run as the user presses a number key to select a number, and then clicks where they would like that number to appear in the grid, and this seems to break Mike - SMT's solution. Any fixes?

like image 869
TDJSB Avatar asked Apr 20 '26 09:04

TDJSB


1 Answers

I would use a list to keep track of each label. Then apply a new text size to the label when the window resizes. You will also need to provide a 1x1 pixel image in order for the label to read its size in pixels vs text height.

I will be using grid() for this but it could just as easily be done with pack().

Because we are using grid() we need to make sure we set weights on each column/row the labels will be set to using rowconfigure() and columnconfigure().

The function we will need should check the height and width of the widget and then based on what number is smaller set the size of the font object. This will prevent the font from growing bigger than the label size.

import tkinter as tk
import tkinter.font as tkFont


root = tk.Tk()
label_list = []
font = tkFont.Font(family="Helvetica")
pixel = tk.PhotoImage(width=1, height=1)

for x in range(3):
    for y in range(3):
        root.rowconfigure(y, weight=1)
        root.columnconfigure(x, weight=1)

        label_list.append(tk.Label(root, width=40, height=40, image=pixel, text=(y * 3 + x) + 1, relief="groove", compound="center"))
        label_list[-1].grid(row=x, column=y, sticky="nsew")

def font_resize(event=None):
    for lbl in label_list:
        x = lbl.winfo_width()
        y = lbl.winfo_height()
        if x < y:
            lbl.config(font=("Courier", (x-10)))
        else:
            lbl.config(font=("Courier", (y-10)))

root.bind( "<Configure>", font_resize)
root.mainloop()

Results:

No mater how you resize the window it should always have roughly the largest the font can be without exceeding the label size.

enter image description here enter image description here enter image description here

UPDATE:

I did change a few things in your code. I changed how you were creating your btn_ID to something less complicated and something we can use with the update method. Let me know if you have any questions.

To answer your changed question and your comment here is a reworked version of your new code to do what you want:

from tkinter import *
import tkinter.font as tkFont

grey = [0,1,2,6,7,8,9,10,11,15,16,17,18,19,20,24,25,26,30,31,32,39,40,41,48,49,50,54,55,56,60,61,62,63,64,65,69,70,71,72,73,74,78,79,80]

class GUI(Frame):
    def __init__(self, master=None):
        Frame.__init__(self, master)
        self.pixel = PhotoImage(width=1, height=1)
        self.font = tkFont.Font(family="Helvetica")
        self.master.bind("<Configure>", self.font_resize)
        self.btn_list = []
        self.filled = []
        self.filled_ID = []

        self.screen_init()

        self.key = None
        self.keydetection = False
        self.detect()
        self.bind_all("<Key>", self.key_event)
        root.bind( "<Configure>", self.font_resize)

    def screen_init(self, master=None):
        btn_ndex = 0
        for x in range(9):
            for y in range(9):
                self.btn_list.append(Button(master, font=self.font, width=40, height=40, image=self.pixel, compound=CENTER, bg="#D3D3D3" if 9 * y + x in grey else "#FFFFFF", command=lambda c=btn_ndex: self.click(c)))
                self.btn_list[-1].grid(row=y, column=x, sticky="nsew")
                root.rowconfigure(y, weight=1)
                root.columnconfigure(x, weight=1)
                btn_ndex += 1

    def font_resize(self, event=None):
        for btn in self.btn_list:
            x = btn.winfo_width()
            y = btn.winfo_height()
            if x < y:
                self.font.configure(size=x-10)
            else:
                self.font.configure(size=y-10)

    def update(self, btn_ID, number=None, colour="#000000", master=None):
        print(btn_ID)
        y = btn_ID // 9
        x = btn_ID % 9
        self.btn_list[btn_ID].config(text=number, fg=colour, bg="#D3D3D3" if 9 * y + x in grey else "#FFFFFF", command=lambda c=9 * y + x: self.click(c))

    def detect(self):
        self.keydetection=not self.keydetection

    def key_event(self, event):
        try:
            self.key=int(event.keysym)
        except:
            print("Numbers Only!")

    def click(self, btn_ID):
        if btn_ID in self.filled:
            self.filled_ID.pop(self.filled.index(btn_ID))
            self.filled.remove(btn_ID)
            window.update(btn_ID)
        else:
            self.filled.append(btn_ID)
            self.filled_ID.append(self.key)
            window.update(btn_ID, self.key)


if __name__ == '__main__':
    root = Tk()
    root.title("Example")
    window = GUI(root)
    root.mainloop()
like image 58
Mike - SMT Avatar answered Apr 22 '26 22:04

Mike - SMT



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!