Python3: How to dynamically resize button text in tkinter/ttk?
The example below shows two techniques, one activated by re-sizing the window (see the resize()
method, bound to the <Configure>
event), and the other by directly changing the size of the font (see the mutate()
method).
Other code necessary to get resizing working is the grid configuration code in the __init__()
method.
When running the example, there is some interaction between the two methods, but I think in a 'real' situation one technique would be sufficient, so that issue won't arise.
from tkinter import *from tkinter.ttk import *class ButtonApp(Frame): """Container for the buttons.""" def __init__(self, master=None): """Initialize the frame and its children.""" super().__init__(master) self.createWidgets() # configure the frame's resize behaviour master.columnconfigure(0, weight=1) master.rowconfigure(0, weight=1) self.grid(sticky=(N,S,E,W)) # configure resize behaviour for the frame's children self.columnconfigure(0, weight=1) self.rowconfigure(0, weight=1) self.rowconfigure(0, weight=1) # bind to window resize events self.bind('<Configure>', self.resize) def createWidgets(self): """Make the widgets.""" # this button mutates self.mutantButton = Button(self, text='Press Me', style='10.TButton') self.mutantButton.grid(column=0, row=0, sticky=(N,S,E,W)) self.mutantButton['command'] = self.mutate # an ordinary quit button for comparison self.quitButton = Button(self, text='Quit', style='TButton') self.quitButton.grid(column=0, row=1, sticky=(N,S,E,W)) self.quitButton['command'] = self.quit def mutate(self): """Rotate through the styles by hitting the button.""" style = int(self.mutantButton['style'].split('.')[0]) newStyle = style + 5 if newStyle > 50: newStyle = 10 print('Choosing font '+str(newStyle)) self.mutantButton['style'] = fontStyle[newStyle] # resize the frame # get the current geometries currentGeometry = self._root().geometry() w, h, x, y = self.parseGeometry(currentGeometry) reqWidth = self.mutantButton.winfo_reqwidth() reqHeight = self.mutantButton.winfo_reqheight() # note assume height of quit button is constant at 20. w = max([w, reqWidth]) h = 20 + reqHeight self._root().geometry('%dx%d+%d+%d' % (w, h, x, y)) def parseGeometry(self, geometry): """Geometry parser. Returns the geometry as a (w, h, x, y) tuple.""" # get w xsplit = geometry.split('x') w = int(xsplit[0]) rest = xsplit[1] # get h, x, y plussplit = rest.split('+') h = int(plussplit[0]) x = int(plussplit[1]) y = int(plussplit[2]) return w, h, x, y def resize(self, event): """Method bound to the <Configure> event for resizing.""" # get geometry info from the root window. wm, hm = self._root().winfo_width(), self._root().winfo_height() # choose a font height to match # note subtract 30 for the button we are NOT scaling. # note we assume optimal font height is 1/2 widget height. fontHeight = (hm - 20) // 2 print('Resizing to font '+str(fontHeight)) # calculate the best font to use (use int rounding) bestStyle = fontStyle[10] # use min size as the fallback if fontHeight < 10: pass # the min size elif fontHeight >= 50: # the max size bestStyle = fontStyle[50] else: # everything in between bestFitFont = (fontHeight // 5) * 5 bestStyle = fontStyle[bestFitFont] # set the style on the button self.mutantButton['style'] = bestStyleroot = Tk()root.title('Alice in Pythonland')# make a dictionary of sized font styles in the range of interest.fontStyle = {}for font in range(10, 51, 5): styleName = str(font)+'.TButton' fontName = ' '.join(['helvetica', str(font), 'bold']) fontStyle[font] = styleName Style().configure(styleName, font=fontName)# run the appapp = ButtonApp(master=root)app.mainloop()root.destroy()