Python Tkinter中的真正自定义字体

Python Tkinter中的真正自定义字体,python,fonts,tkinter,Python,Fonts,Tkinter,我正在做一个Tkinter界面,我需要有自定义字体。比如说,不仅仅是特定尺寸的Helvetica或其他字体,而是任何给定平台上通常可用的字体以外的字体。这将作为图像文件或(最好)Truetype字体文件或类似文件与程序一起保存。我不想在每台使用该程序的机器上都安装所需的字体,我只想将它们与程序放在同一个目录中 tkFont模块看起来应该这样做,但我看不出它在哪里需要一个文件名来表示运行该程序的系统通常无法访问的字体。 提前感谢您的帮助。我找到了他们介绍如何使用一行文本作为图像,并使用PIL将其放

我正在做一个Tkinter界面,我需要有自定义字体。比如说,不仅仅是特定尺寸的Helvetica或其他字体,而是任何给定平台上通常可用的字体以外的字体。这将作为图像文件或(最好)Truetype字体文件或类似文件与程序一起保存。我不想在每台使用该程序的机器上都安装所需的字体,我只想将它们与程序放在同一个目录中

tkFont模块看起来应该这样做,但我看不出它在哪里需要一个文件名来表示运行该程序的系统通常无法访问的字体。 提前感谢您的帮助。

我找到了他们介绍如何使用一行文本作为图像,并使用PIL将其放置到窗口中的内容。这可能是一个解决办法


我找不到使用tkFont在中导入捆绑字体的方法。

如果不借助特定于平台的黑客攻击,就无法将外部字体文件加载到Tkinter中。Tkinter没有内置支持它的功能。

有一种方法可以将外部字体输入Tkinter[Windows] (至少在Windows上)

实现此功能的关键代码是以下函数:

从ctypes导入Windell、byref、创建\u unicode\u缓冲区、创建\u字符串\u缓冲区
FR_PRIVATE=0x10
FR_NOT_ENUM=0x20
def loadfont(fontpath,private=True,enumerable=False):
'''
使文件“fontpath”中的字体可供字体系统使用。
`private`如果为True,则其他进程无法看到此字体,并且
进程结束时将卸载字体
`enumerable`如果为True,则在枚举字体时将显示此字体
看见https://msdn.microsoft.com/en-us/library/dd183327(第85节)
'''
#此函数取自
# https://github.com/ifwe/digsby/blob/f5fe00244744aa131e07f09348d10563f3d8fa99/digsby/src/gui/native/win/winfonts.py#L15
#此函数是为Python2.x编写的。对于3.x,你
#必须将isinstance检查转换为字节和str
如果isinstance(fontpath,str):
pathbuf=创建字符串缓冲区(fontpath)
AddFontResourceEx=windell.gdi32.AddFontResourceExA
elif isinstance(fontpath,unicode):
pathbuf=创建unicode缓冲区(fontpath)
AddFontResourceEx=windell.gdi32.AddFontResourceExW
其他:
raise TypeError('fontpath必须为str或unicode'类型)
flags=(FR_PRIVATE if PRIVATE else 0)|(FR_NOT_ENUM if NOT enumerable else 0)
numFontsAdded=AddFontResourceEx(byref(pathbuf),标志,0)
返回布尔(numFontsAdded)
使用字体文件的路径调用
loadfont
(可以是
.fon
.fnt
.ttf
.ttc
.fot
.otf
.mmm
.pfb
,或
.pfm
)中的任意一种)后,您可以像其他安装的字体一样加载字体
.font(family=XXX,…)
。您可以在任何地方使用它。[有关更多信息,请参阅]

这里最大的警告是,字体的姓氏不一定是文件名;它嵌入在字体数据中。与其尝试解析名称,不如在字体浏览器GUI中查找它,并在应用程序中硬编码。编辑:或者,根据patthoyt下面的评论,查找它在
tkFont.families()
(作为最后一项,或者更确切地说,通过比较加载字体前后的族列表)

我在()中找到了这个函数;如果您想在程序完成执行之前删除字体,则在这里定义了一个
unloadfont
函数。(您也可以在程序结束时依靠
private
设置卸载字体。)


对于任何感兴趣的人,几年前在[TCLCORE]上有一个关于此主题的讨论。更多背景信息:

这对我在windows上有效,但在linux上似乎不起作用:

import pyglet,tkinter
pyglet.font.add_file('file.ttf')

root = tkinter.Tk()
MyLabel = tkinter.Label(root,text="test",font=('font name',25))
MyLabel.pack()
root.mainloop()

这对我来说是一个简单的解决方案:

import pyglet, tkinter
pyglet.font.add_file("your font path here")
#then you can use the font as you would normally

对于linux,我能够将我拥有的
otf
font文件安装到系统字体目录中:

mkdir /usr/share/fonts/opentype/my_fonts_name
cp ~/Downloads/my_fonts_name.otf /usr/share/fonts/opentype/my_fonts_name/
我发现这个主目录有效,并最终使用了它:

mkdir ~/.fonts/
cp ~/Downloads/my_fonts_name.otf ~/.fonts/
在任何一种情况下,我都可以使用字体名称字符串加载它(正如所有tkinter文档所示):


你再也无法打开讨论链接了是的,你是对的。我也找不到讨论的存档。基本上我现在的理解是,你可以使用PIL中的自定义字体渲染文本,然后使用Tkinter将其放入窗口,但我已经有几年没有考虑过这个问题了:).我意识到这是一个老问题,但至少在Windows上,有一种方法可以做到这一点。请看我的答案,首先,被接受的答案有一个断开的链接,所以你可能想考虑改变它。第二,对于自定义字体,我建议查看PyQt或PySide2。它们支持自定义字体。如果您避免传递FR\u NOT\u ENUM,则字体名称在
tkinter.font.families()
中可见。当我测试这个时,它被附加到列表的末尾,所以似乎
tkinter.font.families()[-1]
将是您需要传递给Tk的名称。哦,太好了!您还可以在调用之前保存
tkinter.font.families()
,然后将其与调用
loadfont
后的结果进行比较。字体文件是否仅限于一个族?保存族()结果并使用
[name for name in families()(如果name不在保存列表中)]
效果很好。如果这是由
loadfont
函数返回的,那就更好了——不过这个函数需要加载tkinter。在这种情况下,返回字体的实际数量可能比布尔值更有用。我的测试字体在文件中只有一个面。这对我不起作用——我使用的是Python 3,如果isinstance(fontpath,str):# unshown code self.canvas = tk.Canvas(self.data_frame, background="black") self.canvas.create_text(event.x, event.y, text=t, tags='clicks', fill='firebrick1', font=("My Fonts Name", 22))