不更改Tkinter按钮大小的情况下更改字体大小

8
我在Tkinter中遇到了一个问题,无法更改按钮的字体大小。当我尝试更改时,按钮的大小也会根据文本的大小而扩展/收缩。有没有一种方法可以在固定按钮大小的情况下改变文本大小?
我在设计井字棋应用程序时遇到了这个问题,但为了节省您的麻烦,这里是一个非常简单的示例来说明这个问题:
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()

这里最重要的部分是font=('Helvetica', '15'),具体来说,是数字15。如果你更改该数字并重新运行此代码,则不仅文本变得更大/更小,按钮也会随之调整大小!我该怎么解决这个问题呢?

这可能是一个非常简单的问题。我刚开始使用Tkinter。提前感谢任何给予帮助的人!


你为什么要将字体大小作为字符串而不是数字传递? - martineau
@martineau 嗯,实际上我传递的方式并不重要,但我猜我在网上找到了那种传递方式的文档。 - warspyking
同时导入Tkinter作为tk。你使用的操作系统是什么? - Taku
啊,谢谢 :) @abccd 还有,Linux。 - warspyking
问题出在Button构造函数调用中的height=10。这是指按钮应该有多少行文本高度(而不是像素高度),这取决于所使用字体的字符高度。 - martineau
显示剩余2条评论
3个回答

7
通常情况下,当您为按钮设置宽度时,该宽度以字符为单位进行测量(例如:width=1 表示一个平均大小的字符的宽度)。但是,如果按钮具有图像,则宽度指定像素大小。
按钮可以包含图像和文本,因此一种策略是将1x1像素作为图像放置,以便您可以指定按钮大小(以像素为单位)。当您这样做并更改字体大小时,按钮不会增大,因为它已经被赋予了绝对大小。
以下是说明该技术的示例。运行代码,然后单击“bigger”或“smaller”以查看文本更改大小,但按钮不会变化。
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()

尽管如此,几乎从来没有一个好的理由这样做。如果用户需要更大的字体,整个UI应该适应。Tkinter非常擅长实现这一点,以至于它在大多数情况下都可以默认工作。


这太棒了,易于理解!作为一个标记,此答案是基于python 2.x的,如果要在python 3.x上测试,请将第一行中的Tkinter编辑为tkinter,将第二行中的import tkFont编辑为from tkinter import font,并将以下内容中的tkFont.Font(编辑为font.Font(,然后您就可以开始了! - Xiang
.grid_columnconfigure.grid_rowconfigure中设置minsize选项也可以起作用。 - haccks

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

编辑:根据我从Bryan Oakley学到的知识,这里是一个更加整洁的实现:
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)

我还要补充一点,我非常赞同Bryan的观点:使用这个可能意味着你做错了什么。你应该让tkinter处理大小调整。

你的类声明以及相关内容让我感到害怕。我才刚开始学习Python和Tkinter哈哈。 - warspyking
GUI界面在Python中大量依赖类,许多其他功能也是如此。快来加入吧。 - Novel

1
我找到了这个问题的解决方案。我正在尝试解决一个类似的问题:我想在标签上放置图像。我将图像大小设置为标签大小。当我试图使用命令label.config(image=img)将其放置时,标签的大小会增加。图像具有我设置的大小,因此它没有完全覆盖标签。我正在使用网格管理器。所有大小都不是提前输入的,而是由Tkinter计算出来的。我正在使用grid_columnconfiguregrid_rowconfigure。我发现的解决方案是将带有图像的标签(或在您的情况下是按钮)放置到LabelFrame中,并将grid_propagate设置为False。 代码示例:
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()

字体大小为40和20的结果:

Image for font size 40 Image for font size 20

使用网格管理器创建动态大小的按钮示例:
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()

这是一个晚回答,但或许对某些人有帮助。

你能帮我解决这个问题吗? https://stackoverflow.com/q/67241484/14715170 - sodmzs1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接