如何使Python Tkinter中的文本在按钮和标签中自动调整大小?

3
我在编写Python代码时遇到了一个问题,无法找到解决方法。我有一个tkinter网格,它会自动调整大小以适应所在窗口的大小,但我希望按钮/标签内的文本也能随着新网格的尺寸调整大小。以下是一个基本的示例:
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()

当你拖动窗口扩展它时,我希望文本能够增大。如何实现?

编辑:
麦克 - SMT的解决方案很好,但不适用于我在他回复评论中描述的情况。
这是我的代码:
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()

这意味着当用户按下数字键选择数字,然后单击希望该数字出现在网格中的位置时,代码最初运行时文本不在网格中,这似乎破坏了Mike - SMT的解决方案。有什么修复方法吗?

这个网站上有几个与标签增长或缩小时更改字体大小相关的问题。在提问之前,您是否搜索过它们?例如,Python3:如何在tkinter/ttk中动态调整按钮文本大小?Python/Tkinter:动态扩展字体大小以填充框架 - Bryan Oakley
更新问题并添加新问题是一个不好的做法,原始问题得到回答后这样做会使回答失效,也浪费了回答的努力。好的做法是接受解决原始问题的答案,然后提出另一个问题。stackoverflow是一个问答网站,而不是一个聊天室,在原问题得到回答后不能用新问题取代原问题。 - undefined
4个回答

2
我会使用列表来跟踪每个标签。然后在窗口调整大小时,将新的文本大小应用于标签。您还需要提供一个1x1像素的图像,以便标签读取其像素大小与文本高度。

我将使用grid()来完成此操作,但也可以使用pack()

因为我们正在使用grid(),所以我们需要确保对每个标签设置的列/行设置权重,使用rowconfigure()columnconfigure()

我们需要的函数应该检查部件的高度和宽度,然后根据较小的数字设置字体对象的大小。这将防止字体变得比标签大小更大。

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

结果:

无论您如何调整窗口大小,它应该始终具有最大的字体大小,而不超过标签大小。

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

更新:

我更改了您代码中的一些内容。我将您创建的btn_ID更改为了更简单的方式,并且我们可以使用更新方法。如果您有任何问题,请告诉我。

为回答您修改后的问题和评论,这是您新代码的重新编写版本以实现您的要求:

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

1

你是想要这样吗?我没有做任何小的更改。在第24行,在按钮中,我添加了关键字文本。

btn_list.append(Button(master, width = 40, height = 40, image = pixel, text = (y * 3 + x) + 1, compound = CENTER, bg = "#D3D3D3" if 9 * y + x in grey else "#FFFFFF", command = lambda c = 9 * y + x: self.click(c)))

之前的结果:

enter image description here

点击按钮后删除数字。

enter image description here


1
我稍微修改了你的代码,使它更简单,并且增加了根据窗口和文本大小进行调整的功能,根据当前窗口大小调整文本大小。顺便说一下:你也可以在不使用图像的情况下实现你想要的功能。
from tkinter import Tk, Frame, Button, Grid, GROOVE, N,E,S,W
root = Tk()
root.title("Example")

cellGeomWidth        = 240
cellGeomHeight    = 240
winTitleHeight        = 24
winBorderWidth    = 3
winWidth            = 3*cellGeomWidth+2*winBorderWidth
winHeight            = 3*cellGeomHeight+2*winBorderWidth+winTitleHeight
root.geometry(f"{winWidth}x{winHeight}")
fontSize             = 16

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, 
                    text="  ",
                    font=("Courier", fontSize),
                    relief = GROOVE, 
                    bg = "#D3D3D3" if 9 * y + x in grey else "#FFFFFF", 
                    command = lambda c = 9 * x + y: 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):
            btn_list[btn_ID].configure(text = number)

    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(e=None):
    if e.widget is root:
        newFontSize = int(min(e.width/winWidth, e.height/winHeight)*fontSize)
        print(f"{newFontSize=}")
        for btn in btn_list:
                btn.configure(font=(None, newFontSize))

if __name__ == '__main__':
    window = GUI(root)
    root.bind("<Configure>", font_resize)
    root.mainloop()

你的代码失败的原因是基于Mike - SMT的回答,你对回答中展示的主要代码机制缺乏全面的理解,错误地将其应用于你的特殊情况。

0
在我的情况下,我发现这个方法可以在使用Python中的tkinter编码时起作用: Welcome.place(relx=0.5, rely=0.1,anchor-=CENTER) 显然,您可以更改小部件名称、X轴和Y轴。

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