如何在不知道小部件的字体系列/大小的情况下更改小部件的字体样式?

59

是否有一种方法可以改变一个 Tkinter 组件的字体样式,而不知道该组件的字体系列和字体大小?

使用情况:我们使用标准的Tkinter小部件(如LabelEntryText等)创建我们的UI。当我们的应用程序运行时,我们可能希望通过使用.config()方法动态更改这些小部件的字体样式为粗体和/或斜体。但不幸的是,似乎没有办法指定字体规范而不指定字体系列和大小。

以下是我们想要做的示例,但这两个示例都无法工作:

widget.config(font='bold')
或者
widget.config(font=( None, None, 'bold' ))

3
“font = '-weight bold'” 不是最简单的解决方案吗? - Damian W
8个回答

67

如果你的目标是改变一组或所有小部件的字体,那么使用.config()来改变应用程序字体的方法不如使用更好的方法。

Tk中一个非常棒的功能是“命名字体”,它们在tkinter中作为对象实现。命名字体的优点在于,如果你更新了字体,使用该字体的所有小部件都会自动更新。因此,将小部件配置为使用字体对象后,只需更改字体对象的配置,即可一次性更新所有小部件。

以下是一个快速示例:

import tkinter as tk
import tkinter.font


class App:
    def __init__(self):
        root=tk.Tk()
        # create a custom font
        self.customFont = tkinter.font.Font(family="Helvetica", size=12)

        # create a couple widgets that use that font
        buttonframe = tk.Frame()
        label = tk.Label(root, text="Hello, world", font=self.customFont)
        text = tk.Text(root, width=20, height=2, font=self.customFont)

        buttonframe.pack(side="top", fill="x")
        label.pack(side="top", fill="x")
        text.pack(side="top", fill="both", expand=True)
        text.insert("end","press +/- buttons to change\nfont size")

        # create buttons to adjust the font
        increase_font = tk.Button(root, text="+", command=self.increase_font)
        decrease_font = tk.Button(root, text="-", command=self.decrease_font)

        increase_font.pack(in_=buttonframe, side="left")
        decrease_font.pack(in_=buttonframe, side="left")

        root.mainloop()

    def increase_font(self):
        '''Make the font 2 points bigger'''
        size = self.customFont['size']
        self.customFont.configure(size=size+2)

    def decrease_font(self):
        '''Make the font 2 points smaller'''
        size = self.customFont['size']
        self.customFont.configure(size=size-2)

app=App()

如果您不喜欢这种方法,或者想要基于默认字体创建自定义字体,或者只是更改一个或两个字体以表示状态,您可以使用font.actual来获取给定小部件字体的实际大小。例如:

import tkinter as tk
import tkinter.font

root = tk.Tk()
label = tk.Label(root, text="Hello, world")
font = tkinter.font.Font(font=label['font'])
print(font.actual())

运行以上代码后,我得到以下输出:

{'family': 'Lucida Grande', 
 'weight': 'normal', 
 'slant': 'roman', 
 'overstrike': False, 
 'underline': False, 
 'size': 13}

5
Bryan: 非常感谢!命名字体功能看起来非常方便——你的演示让我想起了如何在浏览器中调整字体大小。在桌面客户端上执行相同操作的能力将令人印象深刻。 .actual() 方法提供了我解决短期任务所需的信息。给这篇文章的读者一个提示:.actual() 返回的是以像素为单位的字体高度,而不是点数。在构造字体元组时使用此值,必须乘以-1,因为Tkinter字体元组期望像素大小为负值(正值表示点数中的字体大小)。 - Malcolm
讲解得非常清楚。谢谢Bryan。我原本计划按照OP的要求进行操作,但我升级到了命名字体,而不是反复更改本地字体。 - KobeJohn
17
在Python 3中,应使用from tk import font而不是import tkFont - Jace Browning
1
在Python 3中仍然无法工作。我需要在示例中重命名“font”或其他东西吗? - Gabriel Staples
@Gabriel:不需要。只需更改导入即可。请查看更新的答案。 - martineau
很棒的解决方案! - BSP

37

仅用于一个标签的情况,缩短为:

from Tkinter import *
import Tkinter as tk
root = tk.Tk()

# font="-weight bold" does your thing
example = Label(root, text="This is a bold example.", font="-weight bold")
example.pack()

root.mainloop()

我可以肯定地确认这个有效。看起来是最简单的解决方案(?) - Damian W
请注意:这不是OP实际想要的功能,他想要的是更改现有对象的字体属性。如果您使用其他字体创建标签,然后使用 font="-weight bold" 配置大小,则可能会得到不同的字体系列。所有这些只是在默认字体中创建一个粗体标签,而不是将现有字体或标签设置为粗体。 - Bryan Oakley
self.myLabel.config(fg='black', font='-weight bold') 这段代码可以用于现有标签! - Gabriel Staples
@GabrielStaples:是的,但如果该标签之前已配置为使用不同的字体,则它不会使用该字体并将其设置为粗体,而只会将其更改为带有粗体设置的默认字体。 - Bryan Oakley

7
如果您正在使用命名字体,则可以使用一些语句来获取所需内容:
import tkFont
wfont = tkFont.nametofont(widget['font'])
wfont.config(weight='bold')

Edited to incorporate B. Oakley's comment.


3
Corfman 表示,如果字体不是命名字体,那么这段代码将失败。例如,定义一个具有类似 ("Helvetica",12,"bold") 的字体的窗口部件,你的代码将无法正常工作。 - Bryan Oakley
Brandon:谢谢你的帮助。我相信将来我会找到使用nametofont技术的地方。 - Malcolm
1
不要更改整个应用程序中命名的字体,只需针对所需的小部件进行复制: wfont = tkFont.nametofont(widget['font']).copy() wfont.config(weight='bold') widget['font'] = wfont - matof

7

只需使用特定小部件的基本属性,假设您想更改标签的字体。您可以使用以下语法:

mlabel = Label(text="Your text", font=("Name of your font",size))

这段代码适用于Python 3.4版本。

1
问题的要点在于用户不知道“您的字体名称”。 - Bryan Oakley
@J.F.Sebastian:None 不一定会改变小部件当前字体的属性。 - Bryan Oakley
@BryanOakley你想说什么?Label(font=(None, size))可以改变字体大小(至少在我的系统上)。 - jfs
@J.F.Sebastian:这个问题是关于如何在现有的小部件或现有字体上更改字体属性(例如:仅更改大小)。如果您执行label.configure(font=(None, size),它不仅会更改字体大小,还会更改字体系列。 - Bryan Oakley
@BryanOakley 您说得对,这个问题假设存在小部件。我从谷歌上着陆到该页面,(None, size) 对于我的用例有效(指定字体大小而不指定标签的字体系列)。 - jfs

2

如果您想获得默认字体而不需要操作或拥有小部件,则可以使用默认字体的通用名称。

#!/usr/bin/env python3
import tkinter
import tkinter.font  # Python3!

tkinter.Tk()
default_font = tkinter.font.Font(font='TkDefaultFont')
print(default_font.actual())

2

我知道这个问题很老,但是为了谷歌上来的人,我还是要回答一下。

如果你只想将文本变大一点,可以输入 font=15。请注意,无论输入什么数字,似乎都会将字体大小设置为15。

如果想要精确的字体大小并且没有更改字体,可以输入font=('TkDefaultFont', 15)

('TkDefaultFont'是tkinter的默认字体)

你可以在创建小部件时使用这些参数,或者稍后使用.config()进行更改。


适用于Python 3.6.4。


1
尽管这个问题已经问了很长时间,但最近我不得不实现一个解决方案,我认为值得分享。函数widget_font_config(...)在Python 2和3上运行。
本质上,获取小部件字体的“当前值”,进行修改,然后将其放回。支持命名字体,并且默认的inplace_f值为True,这意味着命名字体将被保留并就地修改。但是标志也可以设置为False,这将导致使用不同命名字体替换命名字体,以防用户不希望小部件字体的更改渗透到使用命名字体的所有其他小部件中。
def widget_font_config(widget, inplace_f=True, **kwargs):
    import sys
    if sys.version_info[0] == 2:
        import tkFont as tk_font
    else:
        import tkinter.font as tk_font
    inplace_f = kwargs.pop('inplace', inplace_f)
    font = None    
    if widget and 'font' in widget.config():
        current_font = widget.cget('font') #grabs current value
        namedfont_f = False
        try:
            font = tk_font.nametofont(current_font)
            namedfont_f = True
        except:
            font = current_font
        if namedfont_f and inplace_f:
            font.config(**kwargs)
        else:
            font_d = tk_font.Font(font=font).actual()
            font_d.update(**kwargs)
            font = tk_font.Font(**font_d)
            widget.config(font=font)
        widget.update_idletasks()
    return font

if __name__ == '__main__':
    import sys
    pyVers = sys.version_info[0] # .major
    if pyVers == 2:
        import Tkinter as tk, tkFont as tk_font
    else:
        import tkinter as tk, tkinter.font as tk_font
    def go():
        print(widget_font_config(root.label,  slant='roman', underline=1).actual())
        print(widget_font_config(root.button, overstrike=1).actual())
    root = tk.Tk()
    font_s = 'Courier 20 italic'
    font_d = dict(family='Courier', size=10, weight='normal', slant='italic')
    font = tk_font.Font(**font_d)
    root.label = tk.Label(text='Label {}'.format(font_s), font=font_s)
    root.label.pack()
    root.button = tk.Button(text='Button {}'.format(font), font=font, command=go)
    root.button.pack()
    root.mainloop()

我应该提到,这适用于所有字体:命名字体、字体元组、字体描述符等。 - GaryMBloom

1

将以上信息归纳成一个代码片段:

lbl = ttk.Label(blah, blah)   # Make a label
font = tkFont(lbl['font'])    # Get its font
font.config(weight='bold')    # Modify font attributes
lbl['font'] = font            # Tell the label to use the modified font

这允许在使用字体的情况下独立更改字体属性(只要字体支持该属性)。

您还可以实时进行此操作,以创建真正令人作呕的字体效果。


1
这段代码将会失败,因为tkFont是一个模块而不是一个类。即使tkFont做了作者认为的事情,代码仍然可能失败,因为标签中的字体可能是几种不同的格式之一,其中没有一种可以直接用来创建字体。最后,代码中的注释是错误的--你不是“获取它的字体”和“修改它的属性”,而是创建一个全新的字体。 - Bryan Oakley

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