Change font size without messing with Tkinter button size

喜欢而已 提交于 2020-03-18 21:45:34

问题


I am having trouble changing the font size of a button in Tkinter, when I attempt to do it the button also expands/contracts based on the size of the text. Is there a way I can alter the text size with the button's size anchored in place?

I ran across this while designing a tic-tac-toe application, however to save you the trouble, here is a very minimal example of the problem in practice:

import Tkinter as tk

MyWindow = tk.Tk()
MyWindow.geometry("500x550")


button = tk.Button(MyWindow,text="Hello!",width=17,height=10,font=('Helvetica', '20'))
button.grid(row=1, column=1)

MyWindow.mainloop()

The most important part here is font=('Helvetica', '15') or more specifically, the number 15. If you change that number and run this again, not only will the text be bigger/smaller, but so will the button! How do I get around this?

It's probably a really simple problem. I've just gotten started with Tkinter. Thanks in advance for any help I receive!


回答1:


The width of the button is defined in units of character width. In your case the button is defined to be 17 characters wide. So changing the character width by (ie changing the font size) changes the width of the button. AFAIK, the only way around that is to put the button into a Frame, because a Frame can define it's size in pixels. Here's a new kind of Button that does exactly that:

import Tkinter as tk

class Warspyking(tk.Frame):
    '''A button that has it's width and height set in pixels'''
    def __init__(self, master=None, **kwargs):
        tk.Frame.__init__(self, master)
        self.rowconfigure(0, minsize=kwargs.pop('height', None))
        self.columnconfigure(0, minsize=kwargs.pop('width', None))
        self.btn = tk.Button(self, **kwargs)
        self.btn.grid(row=0, column=0, sticky="nsew")
        self.config = self.btn.config

#example usage:
MyWindow = tk.Tk()
MyWindow.geometry("500x550")

from itertools import cycle
fonts = cycle((('Helvetica', '11'),('Helvetica', '15'),('Helvetica', '20')))
def chg():
    button.config(font=next(fonts))

button = Warspyking(MyWindow,text="Click me!",width=200,height=100 ,font=next(fonts), command=chg)
button.grid(row=1, column=1)

MyWindow.mainloop()

EDIT: Based on what I learned from Bryan Oakley, here's a much neater implementation:

class Warspyking(tk.Button):
    def __init__(self, master=None, **kwargs):
        self.img = tk.PhotoImage()
        tk.Button.__init__(self, master, image=self.img, compound='center', **kwargs)

I should also add that I very much agree with Bryan: Using this is probably a sign that you are doing something wrong. You should let tkinter handle sizing.




回答2:


Typically, when you give a button a width, that width is measured in characters (ie: width=1 means the width of one average sized character). However, if the button has an image then the width specifies a size in pixels.  

A button can contain both an image and text, so one strategy is to put a 1x1 pixel as an image so that you can specify the button size in pixels. When you do that and you change the font size, the button will not grow since it was given an absolute size.

Here is an example that illustrates the technique. Run the code, then click on "bigger" or "smaller" to see that the text changes size but the button does not.

import Tkinter as tk
import tkFont

def bigger():
    size = font.cget("size")
    font.configure(size=size+2)

def smaller():
    size = font.cget("size")
    size = max(2, size-2)
    font.configure(size=size)

root = tk.Tk()
font = tkFont.Font(family="Helvetica", size=12)

toolbar = tk.Frame(root)
container = tk.Frame(root)

toolbar.pack(side="top", fill="x")
container.pack(side="top", fill="both", expand=True)

bigger = tk.Button(toolbar, text="Bigger", command=bigger)
smaller = tk.Button(toolbar, text="Smaller", command=smaller)

bigger.pack(side="left")
smaller.pack(side="left")

pixel = tk.PhotoImage(width=1, height=1)
for row in range(3):
    container.grid_rowconfigure(row, weight=1)
    for column in range(3):
        container.grid_columnconfigure(column, weight=1)
        button = tk.Button(container, font=font, text="x",
            image=pixel, compound="center", width=20, height=20)
        button.grid(row=row, column=column)

root.mainloop()

All of that being said, there is almost never a time when this is a good idea. If the user wants a larger font, the whole UI should adapt. Tkinter is really good at making that happen, to the point where it all mostly works by default.




回答3:


I found solution of this problem. I was trying to solve a similar problem: I want to put image on label. I set the image size equal to label size. When I have been trying to put it with command label.config(image=img) the label size grow. The image have the size I set to it, so it didn't cover label completely. I was using grid manager. All size were not entered in advanced but calculated by Tkinter. I was using grid_columnconfigure and grid_rowconfigure. The solution I found is to put this label with image (or button in Your case) to LabelFrame and set grid_propagate to False. Code example:

MyWindow = tk.Tk()
MyWindow.geometry("500x550")

#create LabelFrame (200x200)
label = tk.LabelFrame(MyWindow, width=200, height=200)

#grid manager to set label localization
labelk.grid(row=0, column=0)

#label row and column configure: first argument is col or row id
label.grid_rowconfigure(0, weight=1)
label.grid_columnconfigure(0, weight=1)

#cancel propagation
label.grid_propagate(False)

#Create button and set it localization. You can change it font without changing size of button, but if You set too big not whole will be visible
button = t.Button(label, text="Hello!", font=('Helvetica', '20'))

#Use sticky to button took up the whole label area
button.grid(row=0, column=0, sticky='nesw')

MyWindow.mainloop()

Result for font size 40 and 20:

Example for creating button with dynamic size by grid manager:

MyWindow = tk.Tk()
MyWindow.geometry("500x550")

#Divide frame on 3x3 regions
for col in range(3):
    MyWindow.grid_columnconfigure(col, weight=1)
for row in range(3):
    MyWindow.grid_rowconfigure(row, weight=1)

label = tk.LabelFrame(MyWindow)

#Put label in the middle
label.grid(row=1, column=1, sticky='nesw')
label.grid_propagate(False)
label.grid_rowconfigure(0, weight=1)
label.grid_columnconfigure(0, weight=1)
button = tk.Button(label, text="Hello!", font=('Helvetica', '30'))
button.grid(row=0, column=0, sticky='nesw')
MyWindow.mainloop()

It is late answer, but maybe it will help someone.



来源:https://stackoverflow.com/questions/42840070/change-font-size-without-messing-with-tkinter-button-size

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!