我希望检索当前分配给任意
tkinter.ttk.Label
小部件的字体对象。
(更准确地说,我想获取小部件当前 tkinter.font.Font
实例的确切
配置属性—
family
、size
、weight
、slant
、underline
和 overstrike
) - 为了以编程方式定义相同基本字体的修改变体。)
使用简单的、无主题的内容很容易做到这一点
tkinter.Label
:
import tkinter.font
# Create root object
root = tkinter.Tk()
# Create label widget
label = tkinter.Label( root, text="Hello world!" )
label.pack()
# Get font name (key) from the widget
font_name = label['font']
print( " font_name:", repr(font_name) )
# Get Font instance and print attributes
font = tkinter.font.nametofont( font_name )
for key, value in font.config().items():
print( f"{key:>10}: {repr(value)}" )
# Display the widget
root.mainloop()
上面的程序打印出字体详细信息如下:
font_name: 'TkDefaultFont'
family: 'sans-serif'
size: 10
weight: 'normal'
slant: 'roman'
underline: 0
overstrike: 0
但是,如果我将其更改为使用
tkinter.ttk.Label
而不是 tkinter.Label
...
import tkinter.font
import tkinter.ttk
[...]
# Create label widget
label = tkinter.ttk.Label( root, text="Hello world!" )
label.pack()
...它不再起作用了。这是因为表达式
label['font']
现在返回空字符串而不是有效的 Tkinter 字体名称。空字符串被分配给 font_name
,然后在 nametofont
函数调用中使用,结果是:
font_name: ''
Traceback (most recent call last):
File "fonttest.py", line 14, in <module>
font = tkinter.font.nametofont( font_name )
File "/usr/lib/python3.10/tkinter/font.py", line 23, in nametofont
return Font(name=name, exists=True, root=root)
File "/usr/lib/python3.10/tkinter/font.py", line 87, in __init__
raise tkinter._tkinter.TclError(
_tkinter.TclError: named font font1 does not already exist
如果我进一步更改程序并通过在创建
ttk
对象之后但在创建 root
小部件之前添加以下行来指定命名的 ttk.Label
主题...
# Set up a ttk theme
style = tkinter.ttk.Style()
style.theme_use( 'breeze' )
...我得到了一些不同的结果,但仍然没有有效的字体名称:
font_name: <font object: 'Helvetica 10'>
Traceback (most recent call last):
File "fonttest.py", line 20, in <module>
font = tkinter.font.nametofont( font_name )
File "/usr/lib/python3.10/tkinter/font.py", line 23, in nametofont
return Font(name=name, exists=True, root=root)
File "/usr/lib/python3.10/tkinter/font.py", line 87, in __init__
raise tkinter._tkinter.TclError(
_tkinter.TclError: named font Helvetica 10 does not already exist
请注意
label['font']
如何不再返回字符串(空字符串或其他字符串),而是返回“字体对象”。
添加更多调试打印...
print( " font_name:", repr(font_name) )
print( "font_name.__class__:", font_name.__class__ )
print( "font_name.__str__():", repr(font_name.__str__()) )
print( "dir( font_name ):", dir( font_name ) )
print( "tkinter.font.names():", tkinter.font.names() )
...给我们这个输出:
font_name: <font object: 'Helvetica 10'>
font_name.__class__: <class '_tkinter.Tcl_Obj'>
font_name.__str__(): 'Helvetica 10'
dir( font_name ): ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'string', 'typename']
tkinter.font.names(): ('TkCaptionFont', 'TkSmallCaptionFont', 'TkTooltipFont', 'TkFixedFont', 'TkHeadingFont', 'TkMenuFont', 'TkIconFont', 'TkTextFont', 'TkDefaultFont')
它并不是真正的“字体名称”,也不是
tkinter.font.Font
的实例,而是 _tkinter.Tcl_Obj
类的实例。 dir
输出列出了一个名为 typename
的成员,所以我也添加了这一行...
print( "font_name.typename:", repr(font_name.typename) )
...产生:
font_name.typename: 'font'
总结一下:有时主题
ttk
小部件为其字体返回空字符串,有时它们返回“字体对象”。 “字体对象”(如果存在)不是 tkinter.font.Font
实例,而是 _tkinter.Tcl_Obj
实例 — 显然是内部 TCL font
对象的 Python 包装器,其属性无法被 Python 代码访问?由于这个奇怪的 font
对象
is可转换为字符串 (
Helvetica 10
),因此它可以技术上用作字体查找调用中的 Tkinter“字体名称”。唉,该对象保存或转换成的字符串仍然不是注册的“字体名称”(
tkinter.font.names()
或tkinter.font.nametofont( font_name )
可以识别),因此底层字体的属性仍然无法访问。所以,我的问题是:以编程方式获取当前 tkinter.font.Font
实例(或等效属性详细信息 - family
、
size
、 weight
、 slant
、 underline
)的正确方法是什么,
overstrike
)在明确设置主题和未设置主题时分配给 tkinter.ttk.Label
小部件的字体?上面我的测试环境是Python 3.10.12,标配Kubuntu (Ubuntu) 22.04 LTS。软件包 python3-tk
(版本 3.10.8-1~22.04)和
python3-ttkthemes
(版本 3.2.2+git20220101+07e6509cc6bf-1)是从标准 Ubuntu 存储库手动安装的。tkinter.font.Font
与
tkinter.ttk.Style
类 (tkinter.ttk.Style) 一起解决您的问题,请参阅下面的代码:
import tkinter.font
import tkinter.ttk
from tkinter.font import BOLD, Font
# Create root object
root = tkinter.Tk()
# Set up a ttk theme
stylez = tkinter.ttk.Style()
# style.theme_use( 'breeze' ) ### not used see below
default_font_root = tkinter.font.nametofont(stylez.lookup(root , 'font')).actual()
print('default_font_root : ' , default_font_root)
print("default_font_root size : " , default_font_root['size'])
# Set up a ttk theme
print(stylez.theme_names())
stylez.theme_use(stylez.theme_names()[2])
#same of
stylez.theme_use('default')
#create Font
fontz = Font(root , family = 'Ubuntu', size = 64 , weight = BOLD , underline = 1)
stylez.configure('my.TLabel', font = fontz)
# Create label widget
label = tkinter.ttk.Label(root, text="Hello world!" , style = 'my.TLabel')
label.pack()
print(""""style.lookup("TLabel", "font" : """ , stylez.lookup("TLabel", "font"))
print(""""style.lookup("my.TLabel", "font" : """ , stylez.lookup("my.TLabel", "font"))
label_font = tkinter.font.nametofont(stylez.lookup(label['style'] , 'font')).actual()
label_font_name = tkinter.font.nametofont(stylez.lookup(label['style'] , 'font')).name
print('label_font : ' , label_font, label_font_name)
print("fontz['size'] : ", fontz['size'])
# Display the widget
root.mainloop()
"""
this is used to get available Font families in your system :
from tkinter import Tk, font
root = Tk()
for i in sorted(font.families()):
print('\n',i)
"""