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

Posted

技术标签:

【中文标题】如何在不知道小部件的字体系列/大小的情况下更改小部件的字体样式?【英文标题】:How to change a widget's font style without knowing the widget's font family/size? 【发布时间】:2011-05-03 14:19:33 【问题描述】:

有没有办法在不知道小部件的字体系列和字体大小的情况下更改 Tkinter 小部件的字体样式?

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

以下是我们想做的示例,但这些示例都不起作用:

widget.config(font='bold')

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

【问题讨论】:

font = '-weight bold' 不是最简单的解决方案吗? 【参考方案1】:

有比使用.config() 更改应用程序字体更好的方法,特别是如果您的目标是更改整组小部件(或所有小部件)的字体。

Tk 真正伟大的特性之一是“命名字体”的概念。命名字体的美妙之处在于,如果您更新字体,所有使用该字体的小部件都会自动更新。因此,配置您的小部件一次以使用这些自定义字体,然后更改属性是微不足道的。

这是一个简单的例子:

# python 2 imports
# import Tkinter as tk
# import tkFont

# python 3 imports
import tkinter as tk
import tkinter.font as tkFont


class App:
    def __init__(self):
        root=tk.Tk()
        # create a custom font
        self.customFont = tkFont.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()
        text.pack()
        text.insert("end","press +/- buttons to change\nfont size")

        # create buttons to adjust the font
        bigger = tk.Button(root, text="+", command=self.OnBigger)
        smaller = tk.Button(root, text="-", command=self.OnSmaller)
        bigger.pack(in_=buttonframe, side="left")
        smaller.pack(in_=buttonframe, side="left")

        root.mainloop()

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

    def OnSmaller(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 tkFont

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

当我运行上述命令时,我得到以下输出:

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

【讨论】:

布莱恩:非常感谢!命名字体功能看起来非常方便 - 您的演示让我想起了如何在浏览器中调整字体大小。在桌面客户端中执行相同操作的能力将令人印象深刻。 .actual() 方法为我提供了解决短期任务所需的信息。给这篇文章的读者的注意事项:.actual() 以像素与点为单位返回字体高度。要在构造字体元组时使用此值,必须乘以 -1,因为 Tkinter 字体元组期望以像素为单位的字体大小为负值(正值表示以点为单位的字体大小)。 解释得很好。谢谢你布莱恩。我打算做 OP 想要的,但我升级到命名字体而不是重复更改本地字体。 在 Python 3 中是 from tk import font 而不是 import tkFont 在 Python 3 中仍然无法正常工作。我是否必须在示例中重命名“字体”? @Gabriel:不。只需更改导入。查看更新的答案。【参考方案2】:

虽然问这个问题已经有一段时间了,但我最近不得不实施一个解决方案,我认为值得分享。函数 widget_font_config(...) 在 Python 2 和 3 上运行。

本质上,小部件字体的“当前值”被抓取、修改,然后放回。支持命名字体,并且默认的 inplace_fTrue 意味着命名字体将被保留和修改。但是该标志也可以设置为 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()

【讨论】:

我应该提到这适用于所有字体:命名字体、字体元组、字体描述符等。【参考方案3】:

我知道这个问题真的很老了,但为了谷歌的人,我仍然会回答。

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

如果想要一个精确的大小并且没有改变字体,你可以font=('TkDefaultFont', 15)

'TkDefaultFont' 是 tkinter 的默认字体)

您可以在创建时在小部件的参数中使用其中任何一个,或者稍后使用.config()


适用于 python 3.6.4

【讨论】:

【参考方案4】:

要在不触摸或使用小部件的情况下获得默认字体,您可以使用默认字体的通用名称。

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

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

【讨论】:

【参考方案5】:

如果你使用的是命名字体,你可以使用几个语句来得到你想要的:

import tkFont
wfont = tkFont.nametofont(widget['font'])
wfont.config(weight='bold')

已编辑以纳入 B. Oakley 的评论。

【讨论】:

Corfman:除非字体是命名字体,否则这将失败。例如,使用("Helvetica",12,"bold") 之类的字体定义一个小部件,您的代码将失败。 布兰登:谢谢你的帮助。我相信将来我会找到 nametofont 技术的用途。 不要更改整个应用程序中的命名字体,而只是为了您需要复制它的小部件:wfont = tkFont.nametofont(widget['font']).copy() wfont.config(weight='bold') widget['font'] = wfont【参考方案6】:

一个标签甚至更短:

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

【讨论】:

我可以肯定地确认这是可行的。似乎是最简单的解决方案(?) 注意:这并没有做 OP 真正想要的,即更改现有对象的字体属性。如果您使用其他字体创建标签,然后使用font="-weight bold" 配置大小,您最终可能会使用不同的字体系列。所有这一切都是在默认字体中创建一个粗体标签,而不是将现有字体或标签设置为粗体。 self.myLabel.config(fg='black', font='-weight bold') 这适用于现有标签! @GabrielStaples:是的,但是如果标签之前已配置为使用不同的字体,则不会使用该字体并将其设置为粗体,它只会将其更改为默认字体粗体设置。【参考方案7】:

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

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

此代码适用于 python 3.4

【讨论】:

问题的关键是用户不知道“你的字体名称”。 @J.F.Sebastian: None 不一定会改变小部件当前字体的属性和 @BryanOakley 你想说什么? Label(font=(None, size)) 改变字体大小(至少在我的系统上)。 @J.F.Sebastian:问题是关于如何更改现有小部件或现有字体的字体属性(例如:仅大小)。如果你这样做label.configure(font=(None, size),它不仅会改变字体大小,还会改变字体系列。 @BryanOakley 你是对的,这个问题假设现有的小部件。我已经从谷歌登陆页面,(None, size) 适用于我的用例(指定字体大小而不指定标签的字体系列)。【参考方案8】:

将上述大部分信息归结为单个代码 sn-p:

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

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

您也可以即时执行此操作,以创建真正令人作呕的字体效果。

【讨论】:

这段代码会失败,因为tkFont 是一个模块,而不是一个类。即使tkFont 做了作者的想法,代码仍然会失败,因为标签中的字体可能是几种不同格式中的一种,这两种格式都不能直接用于创建字体。最后,代码中的 cmets 是错误的——你不是在“获取它的字体”和“修改它的属性”,而是在创建一个全新的字体。

以上是关于如何在不知道小部件的字体系列/大小的情况下更改小部件的字体样式?的主要内容,如果未能解决你的问题,请参考以下文章

在不更改应用样式的情况下更改 QSpinBox 箭头大小

如何在不更改字体大小的情况下快速更改 UISegmentedControl 的字体?

WPF:在不知道项目的情况下更改组合框的字体大小

如何在不更改字体本身的情况下更改 uilabel 的字体大小?

如何在 androidx 抽屉布局小部件中更改字体大小和颜色

PyCharm:如何在不使用鼠标滚动缩放的情况下更改字体大小?