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?
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.

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()
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