20

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

tkFont 模块看起来应该做这样的事情,但我看不出它会将文件名用于运行程序的系统通常无法访问的字体的位置。在此先感谢您的帮助。

4

7 回答 7

17

有一种方法可以在 Windows 上将外部字体导入 Tkinter。

完成这项工作的关键代码是以下函数:

from ctypes import windll, byref, create_unicode_buffer, create_string_buffer
FR_PRIVATE  = 0x10
FR_NOT_ENUM = 0x20

def loadfont(fontpath, private=True, enumerable=False):
    '''
    Makes fonts located in file `fontpath` available to the font system.

    `private`     if True, other processes cannot see this font, and this 
                  font will be unloaded when the process dies
    `enumerable`  if True, this font will appear when enumerating fonts

    See https://msdn.microsoft.com/en-us/library/dd183327(VS.85).aspx

    '''
    # This function was taken from
    # https://github.com/ifwe/digsby/blob/f5fe00244744aa131e07f09348d10563f3d8fa99/digsby/src/gui/native/win/winfonts.py#L15
    # This function is written for Python 2.x. For 3.x, you
    # have to convert the isinstance checks to bytes and str
    if isinstance(fontpath, str):
        pathbuf = create_string_buffer(fontpath)
        AddFontResourceEx = windll.gdi32.AddFontResourceExA
    elif isinstance(fontpath, unicode):
        pathbuf = create_unicode_buffer(fontpath)
        AddFontResourceEx = windll.gdi32.AddFontResourceExW
    else:
        raise TypeError('fontpath must be of type str or unicode')

    flags = (FR_PRIVATE if private else 0) | (FR_NOT_ENUM if not enumerable else 0)
    numFontsAdded = AddFontResourceEx(byref(pathbuf), flags, 0)
    return bool(numFontsAdded)

loadfont使用字体文件的路径(可以是.fon.fnt.ttf.ttc.fot.otf.mmm.pfb或中的任何一个.pfm)调用后,您可以像任何其他已安装的字体一样加载字体tkFont.Font(family=XXX, ...)。并在您喜欢的任何地方使用它。[有关详细信息,请参阅MSDN ]

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

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

对于任何感兴趣的人,这里是几年前在 [TCLCORE] 上对此主题的讨论。更多背景知识:MSDN 上的字体

于 2015-06-03T21:44:14.820 回答
8

这在 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()
于 2020-04-21T21:02:13.657 回答
7

如果不借助特定于平台的 hack,就无法将外部字体文件加载到 Tkinter 中。Tkinter 没有内置任何东西来支持它。

于 2012-08-16T21:41:27.697 回答
5

我发现了这个讨论,他们介绍了如何使用一行文本作为图像并使用 PIL 将其放置到窗口中。那可能是一个解决方案。

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

于 2012-08-16T19:10:02.583 回答
2

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

import pyglet, tkinter
pyglet.font.add_file("your font path here")
#then you can use the font as you would normally
于 2020-07-24T23:08:53.517 回答
1

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

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 文档所示):

# 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))
于 2020-11-01T09:14:56.337 回答
0

tkextrafont在我看来是最轻量级和最简单的,它在 PyPI 上为 Windows 和 Linux 提供了预构建的轮子。例子:

import tkinter as tk
from tkextrafont import Font

window = tk.Tk()
font = Font(file="tests/overhaul.ttf", family="Overhaul")
tk.Label(window, text="Hello", font=font).pack()
window.mainloop()
于 2022-02-28T19:04:40.680 回答