【Tkinter】フォントの変更方法2選!tkinter.fontモジュールの解説も!

Tkinterでフォントを設定

こんにちは、Youtaです。

今回は、Tkinterのフォントについてです。

Tkinterにはテキストを入力・表示するウィジェットが数多くあります。

文字列を扱う場面が多いため、次のように思った方もいるでしょう。

すずか
すずか

Tkinterのフォントには何があるん?

先生
先生

全フォントを一覧で見られたら便利ですよね。
簡単にコードを組んでみましたよ。

Tkinterのフォントファミリーの一覧

本記事は、フォント操作に長けたtkinter.fontモジュールの機能をすべて解説します

したがって、Tkinterのフォントに関するお悩みは必ず解消できるはずです。

(上記のフォント一覧出力にも、このモジュールが関与します。)

それでは早速、Tkinterのフォントについて見ていきましょう!

フォントの変更方法

Tkinterで文字列を表示できるウィジェットには、fontオプションがあります。

このfontオプションが、フォントの変更を受け付ける窓口です。

ラベルの文字列のフォントを変更する例です。

import tkinter as tk

# オブジェクト生成時
label = tk.Label(
    font=◯◯, # フォントを指定
)

# configメソッド利用時
label.config(
    font=◯◯, # フォントを指定
)

fontオプションは、コンストラクタ・configメソッドのキーワード引数とします。

またfontオプションに渡す引数の形式により、フォントの変更方法が異なります。

その変更方法とは、下記の\(2\)種類です。

タプルでの変更

タプルでフォントを変更する方法をご紹介します。

イメージとしては、順にパラメータを指定する形です。

font=(family, size, weight, slant, underline, overstrike)

指定可能な\(6\)つのパラメータです。

変数名データ型必須 / 任意説明
family文字列必須フォントファミリー
"Times""Courier"
size文字列・整数必須(size以下の項目を指定する場合)フォントの大きさ
正の整数でポイント単位
負の整数でピクセル単位
weight文字列任意フォントの太さ
太字: "bold"
通常: 指定なし
slant文字列任意フォントの傾斜
斜体: "italic"
通常: 指定なし
underline文字列任意下線の有無
あり: "underline"
なし: 指定なし
overstrike文字列任意取り消し線の有無
あり: "overstrike"
なし: 指定なし
タプルでフォントを変更する際のパラメータ

具体例をお見せしましょう。

import tkinter as tk

label = tk.Label(
    text="Hello, World.",
    font=("Times", 100, "bold", "italic", "underline", "overstrike")
)
label.pack()

label.mainloop()

実行例です。

"Hello, World."とラベルに表示
先生
先生

タプルの代わりに、文字列・リストも使えます。
指定方法は同じです。

# 文字列の場合
label.config(font="Times 20 bold italic underline overstrike")

# リストの場合
label.config(font=["Times", 20, "bold", "italic", "underline", "overstrike"])

次章からは、各パラメータの詳細を説明します。

family

familyフォントの字体(フォントファミリー)を表します。

使用可能なfamilyは、 OS に搭載されているフォントに依存します。

すずか
すずか

familyには何が選べるの?

"Menlo""Times"等が使用可能です。

後ほど、Tkinterで使えるフォントファミリーの一覧を表示する方法をご紹介します。

注意点としては、\(6\)つのパラメータの中で唯一省略ができません。

すずか
すずか

じゃあfamily以外を変えたいときは?

先生
先生

familyにこだわりがなければ、空文字列を指定します。

label.config(font=("", ...))

この場合、デフォルトのフォントが適用されます。

また、無効な文字列を渡した場合もデフォルトのフォントになります。

label.config(font=("Hello, World."))

size

sizeフォントのサイズです。

タプルの場合、int型でもstr型の整数でも指定できます。

# int型
label.config(font=("", 12))

# str型の整数
label.config(font=("", "12"))

正の整数だとポイント単位、負の整数だとピクセル単位です。

また\(0\)を指定すると、デフォルトの文字サイズが適用されます。

label.config(font=("", 12))  # ポイント単位
label.config(font=("", -12))  # ピクセル単位
label.config(font=("", 0))  # デフォルト

続くweightslant等を指定しない場合、sizeは省略できます。

この場合、サイズはデフォルト値になります。

# サイズ省略
label.config(font=("Arial"))  

weightslant等を指定する場合、sizeは省略できないので注意です。

label.config(font=("Arial", "overstrike"))
# _tkinter.TclError: expected integer but got "overstrike"

weightslantunderlineoverstrike

weightslantunderlineoverstrikeは、フォントの修飾に関連します。

それぞれ太字斜体下線取り消し線の設定です。

太字は"bold"、斜体は"italic"、下線は"underline"、取り消し線は"overstrike"の文字列で指定します。

label.config(font=("", 0, "bold", "italic", "underline", "overstrike"))

\(4\)つのオプションの順序は任意です。

label.config(font=("", 0, "italic", "bold", "overstrike", "underline"))  # OK
label.config(font=("", 0, "underline", "bold", "overstrike", "italic"))  # OK

各オプションを空白で区切った\(1\)つの文字列としても渡せます。

label.config(font=("", 0, "bold italic underline overstrike"))

フォントオブジェクトでの変更

フォントオブジェクトでフォントを指定する方法をご紹介します。

フォントオブジェクトはtkinter.fontモジュールFontクラスに属します。

イメージとしては、キーワード引数の形式です。

font=tkinter.font.Font(
    family=◯◯,
    size=◯◯,
    weight=◯◯,
    slant=◯◯,
    underline=◯◯,
    overstrike=◯◯,
)

タプルによるフォント変更と同様のパラメータがあります。

ただし、マーカー部分は先程とは異なる点です。

変数名データ型必須 / 任意説明
family文字列任意フォントの名前(フォントファミリー)
例: "Times""Courier"
size文字列・整数任意フォントの大きさ
正の整数でポイント単位
負の整数でピクセル単位
weight文字列任意フォントの太さ
太字: "bold"tkinter.font.BOLD
通常: "normal"tkinter.font.NORMAL
slant文字列任意フォントの傾斜
斜体: "italic"tkinter.font.ITALIC
通常: "roman"tkinter.font.ROMAN
underlineブール・整数任意下線の有無
あり: True\(1\)
なし: False\(0\)
overstrikeブール・整数任意取り消し線の有無
あり: True\(1\)
なし: False\(0\)
フォントオブジェクトでフォントを変更する際のパラメータ

ただし、\(1\)点だけ注意点があります。

フォントオブジェクトを作る前にTkインスタンス(画面)を作ってください。
Tkインスタンスの代わりに適当なウィジェットでも構いません。

良い例です。

import tkinter as tk
import tkinter.font as tkFont

root = tk.Tk()  # 画面
# label = tk.Label()  # 画面の代わりにウィジェット

font = tkFont.Font()

悪い例です。

import tkinter.font as tkFont

font = tkFont.Font()
# RuntimeError: Too early to use font: no default root window

それでは具体例を見ていきます。

以下、tkinter.fonttkFontと略しています。

import tkinter as tk
import tkinter.font as tkFont

root = tk.Tk()

font = tkFont.Font(
    family="Times",
    size=100,
    weight="bold",  # weight=tkFont.BOLDでもOK
    slant="italic",  # slant=tkFont.ROMANでもOK
    underline=1,
    overstrike=1,
)

label = tk.Label(
    root,
    text="Hello, World.",
    font=font,
)
label.pack()

root.mainloop()

実行例です。

"Hello, World."とラベルに表示

さて、フォントの変更方法を\(2\)つ学びましたが、次のように感じる方も多いと思います。

すずか
すずか

正直タプルの方が楽じゃね。

フォントオブジェクトとか使わんし多分忘れると思う。

先生
先生

私も最初はそう思いました。
しかし、フォントオブジェクトの方が色々都合が良いですよ

せっかく使い方を学んでも、旨みを知らないともったいないですよね。

ということで、あえてフォントオブジェクトを選ぶメリットをまとめます。

フォントオブジェクトの利点

フォントを一括で変更

フォントオブジェクトを使うと、フォントを動的かつ一括で変更できます。

つまり、フォントの変更をリアルタイムでウィジェットに反映させられるのです。

例えば、スピンボックスでフォントのサイズを変える場合。

import tkinter as tk
import tkinter.font as tkFont

root = tk.Tk()
root.geometry("500x500")

# フォントオブジェクトの作成
my_font = tkFont.Font(family="Helvetica", size=1, weight="bold")

# フォントをウィジェットに適用
for i in range(10):
    label = tk.Label(root, text="Hello, World.", font=my_font)
    label.pack()

# 上下ボタンを押すとフォントサイズが変更される
spinbox = tk.Spinbox(root, from_=1, to=20, state="readonly")
spinbox.config(command=lambda: my_font.config(size=spinbox.get()))
spinbox.pack()

root.mainloop()

(configメソッドについては後述。)

my_fontを変更するだけで、全ラベルのフォントが更新されますね。

フォントオブジェクトを参照する全ウィジェットに変更が反映されるのです。

タプルでのフォント変更では、このような芸当はできません。

各ラベルごとにフォントの再設定が必要だからです。

フォントの設定を頻繁に変える場合、フォントオブジェクトの利用を強く推奨します。

フォントの設定を確認

フォントオブジェクトを使用すると、フォントの設定値を詳細に確認できます。

一応タプルの場合でも確認できますが、情報量とその扱いやすさが桁違いなのです。

両者を比較してみましょう。

import tkinter as tk
import tkinter.font as tkFont

root = tk.Tk()
root.geometry("500x500")

# フォントオブジェクトでフォント指定
my_font = tkFont.Font(family="Helvetica", size=1, weight="bold")
label1 = tk.Label(root, text="Hello, World.", font=my_font)

# タプルでフォント指定
label2 = tk.Label(root, text="Hello, World.", font=("Helvetica", 1, "bold"))

# フォント設定を確認
print(my_font.config())
# {'family': 'Helvetica', 'size': 1, 'weight': 'bold', 'slant': 'roman', 'underline': 0, 'overstrike': 0}

print(label2.cget("font"))
# Helvetica 1 bold

フォントオブジェクトの場合は、未指定のslantunderline等の情報も取れます。

print(my_font.config())
# {'family': 'Helvetica', 'size': 1, 'weight': 'bold', 'slant': 'roman', 'underline': 0, 'overstrike': 0}

(configメソッドについては後述。)

さらには、個別にオプションを確認できるメソッドもあるのです。

print(my_font.cget("family"))
# Helvetica

print(my_font.cget("size"))
# 1

(cgetメソッドについては後述。)

一方タプルの場合、指定したオプションの情報しか取れません。

print(label2.cget("font"))
# Helvetica 1 bold

しかもHelvetica 1 boldで\(1\)つの文字列なので、超扱いにくいですよね。

このメリットは主にデバッグ時に重宝されます。

「フォントがおかしいな」と感じたら、簡単に設定を確認できるのです。

tkinter.fontモジュール

フォントオブジェクトはtkinter.fontモジュールのFontクラスに属するのでした。

tkinter.fontモジュールは、Tkinterでのフォント操作に関する機能を提供します。

すずか
すずか

じゃあこれ全部覚えれば最強じゃん。

先生
先生

それが可能かはわかりませんが、
Tkinterでフォントに悩まなくなるでしょうね。

上記の考えのもと、本章ではtkinter.fontモジュールを隅から隅まで解説します。

本章を読み終わる頃には、あなたはきっとフォントマスターになっているでしょう。

(一部どうしてもわからなかった項目もありますが、全機能の9割はカバーしています。)

それでは早速、下記の項目に沿って解説していきます。

tkinter.fontモジュールの機能

Fontクラス

フォントオブジェクトの元であるFontクラスに焦点を当てます。

実は、Fontクラスには\(7\)つのメソッドが存在します。

コンストラクタ

Fontクラスのコンストラクタです。

\(5\)種類の引数があります。

変数名データ型必須 / 任意説明
root親ウィジェット(通常はTkクラス)任意親ウィジェット
fontタプル・文字列任意フォントの設定
name文字列任意フォントの名前
指定の名前でフォントオブジェクトを生成。
existsブール・整数任意Trueで既存のフォントオブジェクトを取得。
Falseがデフォルト。
options(キーワード引数)任意フォントの設定
第二引数fontを指定すると無効化。
コンストラクタの引数

詳細は下記にまとめます。

rootはフォントオブジェクトの親ウィジェットです。

正直指定しなくても内部で上手いことやってくれるので、重要度は低めです。

一応何でも指定できますが、Tkインスタンス(画面)が普通です。

import tkinter as tk
import tkinter.font as tkFont

root = tk.Tk()
font1 = tkFont.Font(root)  # OK

frame = tk.Frame(root)
font2 = tkFont.Font(frame)  # OK

spinbox = tk.Spinbox(frame)
font3 = tkFont.Font(spinbox)  # OK

fontはフォントオブジェクトのフォントの設定を変更します。

タプルでのフォントの変更方法がそのまま使えます。

import tkinter as tk
import tkinter.font as tkFont

root = tk.Tk()

font = tkFont.Font(font=("Times", 12, "bold"))  # タプル

nameはフォントオブジェクトに名前を付けます。

print文でフォントオブジェクトを出力した際、nameで指定した値が出ます。

import tkinter as tk
import tkinter.font as tkFont

root = tk.Tk()

font = tkFont.Font(name="named font")
print(font)
# named font

ちなみにnameを省略した場合は勝手に名前がつけられます。

import tkinter as tk
import tkinter.font as tkFont

root = tk.Tk()

my_font1 = tkFont.Font()
print(my_font1)
# font1

my_font2 = tkFont.Font()
print(my_font2)
# font2

my_font3 = tkFont.Font()
print(my_font3)
# font3
すずか
すずか

だから何なの?

先生
先生

現時点ではnameの意義が不明瞭かも知れません。

ですが、次のexistsと組み合わせて真価を発揮しますよ。

existsTrueにすると、既存のフォントオブジェクトを参照します。

existsの使用は、name引数で名付けられたフォントオブジェクトが既に存在するのを前提とします(例外あり)。

Falseにしたりexists自体を省略すると、新しいフォントオブジェクトを生成します。

すずか
すずか

ちょっと何言ってるかわかんないわー。

先生
先生

具体例を通しましょう。

下記コードをご覧ください。

import tkinter as tk
import tkinter.font as tkFont

root = tk.Tk()

# まず新しいフォントを作成
original_font = tkFont.Font(name='original font', font=('Times', 100, 'italic'))

# 既存のフォントを再利用
reuse_font = tkFont.Font(name='original font', exists=True)

# ラベルにフォントを適用
label1 = tk.Label(root, text="Hello, World.", font=original_font)
label1.pack()

label2 = tk.Label(root, text="Hello, World.", font=reuse_font)
label2.pack()

root.mainloop()

まずはoriginal_fontを新規フォントとして作ります。

また、このときにname引数で'original font'と名前付けをします。

original_font = tkFont.Font(name='original font', font=('Times', 100, 'italic'))

次にoriginal_fontとは別のreuse_fontを作ります。

nameoriginal_fontと同一の'original font'にし、existsTrueにします。

reuse_font = tkFont.Font(name='original font', exists=True)

これにより、reuse_fontoriginal_fontを参照するようになります。

label1original_fontを、label2reuse_fontを適用します。

label1 = tk.Label(root, text="Hello, World.", font=original_font)
label1.pack()

label2 = tk.Label(root, text="Hello, World.", font=reuse_font)
label2.pack()

確かに\(2\)つのラベルは同一のフォントになっています。

2つのラベルが同一のフォントオブジェクトを参照する例

またoriginal_fontでのフォントの変更はreuse_fontで自動更新されます。

試しにmainloopの直前で、取り消し線をoriginal_fontのみに適用してみましょう。

...

original_font.config(overstrike=1)

root.mainloop()

reuse_fontを適用した下のラベルにも取り消し線が反映されています。

上下のラベルに取り消し線が引かれている図

逆もまた然りで、original_fontreuse_fontを参照しています。

取り消し線をreuse_fontのみに適用しても、上記の結果が得られます。

...

reuse_font.config(overstrike=1)

root.mainloop()

最後にexistsの注意点をまとめます。

どのフォントオブジェクトにも付けていないnameを参照させようとしてはいけません。

reuse_font = tkFont.Font(name='Hello, World.', exists=True)
# _tkinter.TclError: named font Hello, World. does not already exist

逆に、同じnameを持つフォントオブジェクトを参照しなくても怒られます。

original_font = tkFont.Font(name='original font')

reuse_font = tkFont.Font(name='original font', exists=False)
# _tkinter.TclError: named font "original font" already exists

# existsはデフォルトでFalse
reuse_font = tkFont.Font(name='original font')
# _tkinter.TclError: named font "original font" already exists

optionsフォントの設定を変更するキーワード引数です。

すずか
すずか

第二引数のfontと役割被ってない?

先生
先生

確かに役割は同じです。
ですが、指定方法が異なります。

下記のように使います。

import tkinter as tk
import tkinter.font as tkFont

root = tk.Tk()

font = tkFont.Font(
    family="Times",
    size=26,
    weight="bold",  # weight=tkFont.BOLDでもOK
    slant="roman",  # slant=tkFont.ROMANでもOK
    underline=1,
    overstrike=1,
)
すずか
すずか

なんかどっかで見た気がするなー。

そう、先程のフォントオブジェクトでのフォントの変更そのものです。

つまりFontクラスは、タプルでもキーワード引数でもフォント変更が可能なのです。

import tkinter as tk
import tkinter.font as tkFont

root = tk.Tk()

# タプルでのフォント指定
font1 = tkFont.Font(font=("Times", 12, "bold"))

# キーワード引数でのフォント指定
font2 = tkFont.Font(
    family="Times",
    size=26,
    weight="bold",  # weight=tkFont.BOLDでもOK
    slant="roman",  # slant=tkFont.ROMANでもOK
    underline=1,
    overstrike=1,
)
すずか
すずか

じゃあfontoptions両方使うとどうなるの?

先生
先生

両者を同時に使うと、optionsが無視されます。

実際fontと共に使うと、optionsに無意味な引数を渡してもエラーすら出ません。

import tkinter as tk
import tkinter.font as tkFont

root = tk.Tk()

# fontとoptions
font1 = tkFont.Font(
    font=("Times", 12, "bold"),
    size="Hello, World.",
)

# optionsのみ
font2 = tkFont.Font(
    size="Hello, World.",
)
# _tkinter.TclError: expected integer but got "Hello, World."

actual(option=None, displayof=None)

actualメソッドは、フォントの実際の属性を取得します。

先生
先生

属性とはfamilysize等の\(6\)つのパラメータです。

設定値ではなく、システムの実際の表示値を取得する点がポイントです。

そのため、もしかすると「指定した値と違うじゃん!」となるかも知れません。

(私の環境では起こりませんでした。)

引数は\(2\)つあります。

変数名データ型必須 / 任意説明
option文字列任意取得するフォント属性
指定しない場合は全属性を辞書形式で取得。
displayofウィジェット任意属性を取得する際に基準とするウィジェット
指定しない場合はルートウィンドウが基準。
actualメソッドの引数

optionには取得したいフォント属性を指定します。

import tkinter as tk
import tkinter.font as tkFont

root = tk.Tk()

font = tkFont.Font(font=("Times", 12, "bold"))

family = font.actual("family")
size = font.actual("size")
weight = font.actual("weight")
slant = font.actual("slant")
underline = font.actual("underline")
overstrike = font.actual("overstrike")

print(family, size, weight, slant, underline, overstrike)
# Times 12 bold roman 0 0

指定しないと、全属性を辞書形式で得られます。

import tkinter as tk
import tkinter.font as tkFont

root = tk.Tk()

font = tkFont.Font(font=("Times", 12, "bold"))

print(font.actual())
# {'family': 'Times', 'size': 12, 'weight': 'bold', 'slant': 'roman', 'underline': 0, 'overstrike': 0}

displayofには、属性を取得する際に基準とするウィジェットを指定します。

省略すると、デフォルトでルートウィンドウが指定されます。

信頼できる情報源からの引用です。

While rare, it’s possible to have multiple windows displaying on multiple displays with different pixel densities. If you have such a setup, this lets you decide which widget/display to use as the basis for determining the size of the string.

(以下、私の訳です。)

稀なケースですが、異なるピクセル密度を持つディスプレイ間に、複数のウィンドウを展開できます。この場合、本引数でどのウィジェット・ディスプレイを基準に文字のサイズを取得するかを決められます。

https://stackoverflow.com/questions/48733568/displayof-in-tkinter-font-font-measure

displayofについては情報が少なく、私も完全には理解していません。

上記の情報をもとにすると、次のようなイメージなるかと思います。

actualメソッドの第二引数displayofの予想される使用方法

displayofに詳しい方は、ご連絡いただけると幸いです。

cget(option)

cgetメソッドは特定の属性の設定値を取得します。

引数optionは必須で、属性を文字列で渡します。

設定した属性をcgetメソッドで取得する例です。

import tkinter as tk
import tkinter.font as tkFont

root = tk.Tk()

font = tkFont.Font(font=("Times", 12, "bold"))

print(font.cget("family"))
# Times
すずか
すずか

さっきのautualメソッドと何が違うの?

autualメソッドは各環境に応じた実際の属性の表示値を取得します。

一方cgetメソッドは属性の設定値を取得します。

(とはいえ、私の環境では両者ともにまったく同じ値ですが・・・。)

config(**options)

configメソッドはフォントの設定を変更します。

引数はコンストラクタのoptionsと同様、キーワード引数で渡します。

import tkinter as tk
import tkinter.font as tkFont

root = tk.Tk()

# 初期設定
font = tkFont.Font(font=("Times", 12, "bold"))
print(font.cget("family"), font.cget("size"), font.cget("weight"))
# Times 12 bold

# configメソッド
font.config(family="Courier", size=18, weight="normal")
print(font.cget("family"), font.cget("size"), font.cget("weight"))
# Courier 18 normal

また、引数を指定しないと全属性の設定値を辞書形式で取得できます。

print(font.config())
# {'family': 'Courier', 'size': 18, 'weight': 'normal', 'slant': 'roman', 'underline': 0, 'overstrike': 0}

cgetメソッドの上位互換とも言えますね。

copy()

copyメソッドはフォントオブジェクトの複製を返します。

import tkinter as tk
import tkinter.font as tkFont

root = tk.Tk()

original_font = tkFont.Font(font=('Times', 100, 'italic'))
replica_font = original_font.copy()

# original_fontを適用
label1 = tk.Label(root, text="Hello, World.", font=original_font)
label1.pack()

# replica_fontを適用
label2 = tk.Label(root, text="Hello, World.", font=replica_font)
label2.pack()

root.mainloop()

どちらのラベルも同じフォントが反映されています。

2つのラベルに同一のフォントを適用する例

ただし、複製した方はオリジナルと属性が同じだけのまったくの別物です。

つまり、オリジナルを参照していません。

したがって、先程見たような変更の同期は起こりません。

試しにmainloopの直前でoriginal_fontの属性を変えてみてください。

...

original_font.config(overstrike=1)

root.mainloop()

original_fontの変更がreplica_fontに反映されないのが確認できます。

上のラベルには取り消し線が引かれているが、下のラベルには引かれていない図

measure(text, displayof=None)

measureメソッドは、文字列が占める幅をピクセル単位で返します。

引数は下記の\(2\)つです。

変数名データ型必須 / 任意説明
text文字列任意幅を測定する文字列
displayofウィジェット任意幅を測定する際に基準とするウィジェット
指定しない場合はルートウィンドウが基準。
measureメソッドの引数

displayofの詳細actualメソッドの章で解説したので割愛します。

measureメソッドで文字幅を取得する例です。

数値は私の環境のものです。

import tkinter as tk
import tkinter.font as tkFont

root = tk.Tk()

text_to_measure = "Hello, World."

small_font = tkFont.Font(size=12)
print(small_font.measure(text_to_measure))
# 74

large_font = tkFont.Font(size=24)
print(large_font.measure(text_to_measure))
# 132

metrics(*options, **kw)

metricsメソッドは、optionsで指定した項目におけるフォントの測定値を取得します。

optionsには下記の項目から\(1\)つを選びます。

変数名説明
"ascent"ベースラインからフォントの一番上までの距離
単位はピクセル
"descent"ベースラインからフォントの一番下までの距離
単位はピクセル単位
"linespace"行間のスペース
単位はピクセル単位
"fixed"フォントが等幅かどうかを示すフラグ
等幅: \(1\)
非等幅: \(0\)
metricsメソッドのoptions引数に選択可能な項目

optionsを指定しないと、全項目の測定値が辞書形式で取得できます。

import tkinter as tk
import tkinter.font as tkFont

root = tk.Tk()

font = tkFont.Font()

print(font.metrics())
# {'ascent': 13, 'descent': 3, 'linespace': 16, 'fixed': 0}

また、kw引数にはdisplayofが指定できます。

キーワード引数なので、displayof=◯◯という形で渡しましょう。

displayofの詳細actualメソッドの章で解説したので割愛します。

ascent・descent・linespaceとは?

ascentdescentは、ベースラインからそれぞれフォントの上・下までの距離です。

linespace行の高さを表し、一般的にはascentdescentの和に一致します。

\(3\)つとも単位はピクセルです。

実際に文字に上方線・下方線・ベースラインを引いてみましょう。

import tkinter as tk
import tkinter.font as tkFont

root = tk.Tk()

# フォント設定を指定する
font = tkFont.Font(size=100)

# フォントのメトリクスを取得する
descent = font.metrics("descent")  # フォントの下降部分の高さ
linespace = font.metrics("linespace")  # 行間の高さ

# 描画するテキスト
text = "Sample Text"
text_width = font.measure(text)  # テキストの幅を測定する

# キャンバスの高さをテキスト幅の半分に設定する
canvas_height = text_width * 0.5

# 文字の境界ボックスの上端と下端を計算する
bbox_top = (canvas_height - linespace) / 2
bbox_bottom = (canvas_height + linespace) / 2

# キャンバスの設定
canvas = tk.Canvas(root, width=text_width, height=canvas_height, highlightthickness=0)
canvas.pack()

# テキストをキャンバスに中央揃えで描画する
canvas.create_text(text_width / 2, canvas_height / 2, text=text, font=font)

# 上方線、下方線、及びベースラインを示す線を描画する
canvas.create_line(0, bbox_top, text_width, bbox_top)  # 上方線
canvas.create_line(0, bbox_bottom, text_width, bbox_bottom)  # 下方線
canvas.create_line(0, bbox_bottom - descent, text_width, bbox_bottom - descent)  # ベースライン

root.mainloop()

実行例です。

各文字が等幅(fixed)とは?

fixed各文字が同一の幅かどうかを示すフラグです。

戻り値はTrueFalseではなく\(1\)・\(0\)です。

多くのフォントは各文字が等幅ではありません。

import tkinter as tk
import tkinter.font as tkFont

root = tk.Tk()

font = tkFont.Font()

print(font.metrics("fixed"))
# 0

しかし、Tkinter標準搭載のTkFixedFontだと文字が等幅になります。

import tkinter as tk
import tkinter.font as tkFont

root = tk.Tk()

font = tkFont.Font(name="TkFixedFont", exists=1)

print(font.metrics("fixed"))
# 1

関数

tkinter.fontモジュールに定義されている関数の紹介です。

次の\(3\)つを順に解説します。

families(root=None, displayof=None)

families関数は、利用可能なフォントファミリーの一覧をタプルで取得します。

引数のrootdisplayofにはTkinterのウィジェットが指定できます。

しかし、両者の違いを述べた情報は見つけることができませんでした。

引数なしでも問題なく動くので、あまり気にしなくても良いと思います。

私の環境で使用可能な全フォントファミリーを出力した結果です。

import tkinter as tk
import tkinter.font as tkFont

root = tk.Tk()

print(tkFont.families())
# ('Academy Engraved LET', 'Adelle Sans Devanagari', 'AkayaKanadaka', 'AkayaTelivigala', 'Al Bayan', 'Al Nile', 'Al Tarikh', 'American Typewriter', 'Andale Mono', 'Annai MN', 'Apple Braille', 'Apple Chancery', 'Apple Color Emoji', 'Apple LiGothic', 'Apple LiSung', 'Apple SD Gothic Neo', 'Apple Symbols', 'AppleGothic', 'AppleMyungjo', 'Arial', 'Arial Black', 'Arial Hebrew', 'Arial Hebrew Scholar', 'Arial Narrow', 'Arial Rounded MT Bold', 'Arial Unicode MS', 'Arima Koshi', 'Arima Madurai', 'Avenir', 'Avenir Next', 'Avenir Next Condensed', 'Ayuthaya', 'Baghdad', 'Bai Jamjuree', 'Baloo 2', 'Baloo Bhai 2', 'Baloo Bhaijaan', 'Baloo Bhaina 2', 'Baloo Chettan 2', 'Baloo Da 2', 'Baloo Paaji 2', 'Baloo Tamma 2', 'Baloo Tammudu 2', 'Baloo Thambi 2', 'Bangla MN', 'Bangla Sangam MN', 'Baoli SC', 'Baoli TC', 'Baskerville', 'Beirut', 'BiauKaiHK', 'BiauKaiTC', 'Big Caslon', 'BIZ UDGothic', 'BIZ UDMincho', 'BM Dohyeon', 'BM Hanna 11yrs Old', 'BM Hanna Air', 'BM Hanna Pro', 'BM Jua', 'BM Kirang Haerang', 'BM Yeonsung', 'Bodoni 72', 'Bodoni 72 Oldstyle', 'Bodoni 72 Smallcaps', 'Bodoni Ornaments', 'Bradley Hand', 'Brush Script MT', 'Cambay Devanagari', 'Chakra Petch', 'Chalkboard', 'Chalkboard SE', 'Chalkduster', 'Charm', 'Charmonman', 'Charter', 'Cochin', 'Comic Sans MS', 'Copperplate', 'Corsiva Hebrew', 'Courier New', 'Damascus', 'DecoType Naskh', 'Devanagari MT', 'Devanagari Sangam MN', 'Didot', 'DIN Alternate', 'DIN Condensed', 'Diwan Kufi', 'Diwan Thuluth', 'Euphemia UCAS', 'Fahkwang', 'Farah', 'Farisi', 'Futura', 'Galvji', 'GB18030 Bitmap', 'Geeza Pro', 'Geneva', 'Georgia', 'Gill Sans', 'Gotu', 'Grantha Sangam MN', 'Gujarati MT', 'Gujarati Sangam MN', 'GungSeo', 'Gurmukhi MN', 'Gurmukhi MT', 'Gurmukhi Sangam MN', 'Hannotate SC', 'Hannotate TC', 'HanziPen SC', 'HanziPen TC', 'HeadLineA', 'Hei', 'Helvetica', 'Helvetica Neue', 'Herculanum', 'Hoefler Text', 'Hubballi', 'Impact', 'InaiMathi', 'ITF Devanagari', 'ITF Devanagari Marathi', 'Jaini', 'Jaini Purva', 'K2D', 'Kai', 'Kailasa', 'Kaiti SC', 'Kaiti TC', 'Kannada MN', 'Kannada Sangam MN', 'Katari', 'Kavivanar', 'Kefa', 'Khmer MN', 'Khmer Sangam MN', 'Kodchasan', 'Kohinoor Bangla', 'Kohinoor Devanagari', 'Kohinoor Gujarati', 'Kohinoor Telugu', 'KoHo', 'Kokonor', 'Krub', 'Krungthep', 'KufiStandardGK', 'Lahore Gurmukhi', 'Lantinghei SC', 'Lantinghei TC', 'Lao MN', 'Lao Sangam MN', 'Lava Devanagari', 'Lava Kannada', 'Lava Telugu', 'Libian SC', 'Libian TC', 'LiHei Pro', 'LingWai SC', 'LingWai TC', 'LiSong Pro', 'Lucida Grande', 'Luminari', 'Maku', 'Malayalam MN', 'Malayalam Sangam MN', 'Mali', 'Marker Felt', 'Menlo', 'Microsoft Sans Serif', 'Mishafi', 'Mishafi Gold', 'Modak', 'Monaco', 'Mshtakan', 'Mukta', 'Mukta Mahee', 'Mukta Malar', 'Mukta Vaani', 'Muna', 'Myanmar MN', 'Myanmar Sangam MN', 'Nadeem', 'Nanum Brush Script', 'Nanum Gothic', 'Nanum Myeongjo', 'Nanum Pen Script', 'New Peninim MT', 'Niramit', 'Noteworthy', 'Noto Nastaliq Urdu', 'Noto Sans Batak', 'Noto Sans Kannada', 'Noto Sans Myanmar', 'Noto Sans NKo', 'Noto Sans Oriya', 'Noto Sans Tagalog', 'Noto Serif Kannada', 'Noto Serif Myanmar', 'October Compressed Devanagari', 'October Compressed Tamil', 'October Condensed Devanagari', 'October Condensed Tamil', 'October Devanagari', 'October Tamil', 'Optima', 'Oriya MN', 'Oriya Sangam MN', 'Osaka', 'Padyakke Expanded One', 'Palatino', 'Papyrus', 'Party LET', 'PCMyungjo', 'Phosphate', 'PilGi', 'PingFang HK', 'PingFang SC', 'PingFang TC', 'Plantagenet Cherokee', 'PSL Ornanong Pro', 'PT Mono', 'PT Sans', 'PT Sans Caption', 'PT Sans Narrow', 'PT Serif', 'PT Serif Caption', 'Raanana', 'Rockwell', 'Sama Devanagari', 'Sama Gujarati', 'Sama Gurmukhi', 'Sama Kannada', 'Sama Malayalam', 'Sama Tamil', 'Sana', 'Sarabun', 'Sathu', 'Savoye LET', 'Shobhika', 'Shree Devanagari 714', 'SignPainter', 'Silom', 'SimSong', 'Sinhala MN', 'Sinhala Sangam MN', 'Skia', 'Snell Roundhand', 'Songti SC', 'Songti TC', 'Srisakdi', 'STFangsong', 'STHeiti', 'STIX Two Math', 'STIX Two Text', 'STKaiti', 'STSong', 'Sukhumvit Set', 'Symbol', 'Tahoma', 'Tamil MN', 'Tamil Sangam MN', 'Telugu MN', 'Telugu Sangam MN', 'Thonburi', 'Times New Roman', 'Tiro Bangla', 'Tiro Devanagari Hindi', 'Tiro Devanagari Marathi', 'Tiro Devanagari Sanskrit', 'Tiro Gurmukhi', 'Tiro Kannada', 'Tiro Tamil', 'Tiro Telugu', 'Trattatello', 'Trebuchet MS', 'Verdana', 'Waseem', 'Wawati SC', 'Wawati TC', 'Webdings', 'Wingdings', 'Wingdings 2', 'Wingdings 3', 'Xingkai SC', 'Xingkai TC', 'Yuanti SC', 'Yuanti TC', 'Yuppy SC', 'Yuppy TC', 'Zapf Dingbats', 'Zapfino', 'Klee', 'Hiragino Sans GB', 'Hiragino Sans CNS', 'Hiragino Sans', 'Hiragino Maru Gothic ProN', 'Hiragino Mincho ProN', 'Heiti SC', 'Heiti TC', 'Tsukushi A Round Gothic', 'Tsukushi B Round Gothic', 'Toppan Bunkyu Gothic', 'Toppan Bunkyu Midashi Gothic', 'Toppan Bunkyu Midashi Mincho', 'Toppan Bunkyu Mincho', 'YuGothic', 'YuKyokasho', 'YuKyokasho Yoko', 'YuMincho', 'YuMincho +36p Kana')

また、全フォントのデザインを確認する方法も載せておきます。

import tkinter as tk
import tkinter.font as tkFont

def show_font_popup(font_family):
    popup = tk.Toplevel()
    popup.title(font_family)
    label = tk.Label(popup, text=font_family, font=(font_family, 100))
    label.pack(padx=10, pady=10)

def on_mouse_wheel(event):
    if event.delta > 0:
        canvas.yview_scroll(-1, 'units')
    elif event.delta < 0:
        canvas.yview_scroll(1, 'units')

root = tk.Tk()
root.title("Available Fonts")

# フォントファミリーを取得
font_families = tkFont.families()

# キャンバスウィジェットを作成してスクロール可能にする
canvas = tk.Canvas(root, borderwidth=0)
frame = tk.Frame(canvas)
scrollbar = tk.Scrollbar(root, orient="vertical", command=canvas.yview)
canvas.configure(yscrollcommand=scrollbar.set)

scrollbar.pack(side="right", fill="y")
canvas.pack(side="left", fill="both", expand=True)
canvas.create_window((4, 4), window=frame, anchor="nw")

frame.bind("<Map>", lambda e: canvas.configure(scrollregion=canvas.bbox("all")))
canvas.bind_all("<MouseWheel>", on_mouse_wheel)

# ラベルの幅と高さを設定
button_width = 20  # 文字数での幅
button_height = 1  # 行数での高さ

# ウィンドウのサイズ
window_width = root.winfo_screenwidth()
window_height = root.winfo_screenheight()

# 1行あたりのラベル数を計算
num_columns = window_width // (button_width * 10)
num_rows = (len(font_families) + num_columns - 1) // num_columns

# グリッド配置
for index, font_family in enumerate(font_families):
    row = index // num_columns
    column = index % num_columns

    button = tk.Button(frame, text=font_family, font=(font_family, 8), width=button_width, height=button_height, anchor="w")
    button.grid(row=row, column=column, padx=5, pady=2, sticky="nsew")
    button.bind("<Button-1>", lambda e, font_family=font_family: show_font_popup(font_family))

root.mainloop()

そう、冒頭で見た図です。

画像サイズの影響で横が見切れていますが、横にウィンドウを引き伸ばせます。

Tkinterのフォントファミリーの一覧

気になるフォントをクリックすると、ポップアップを表示します。

タイトルにフォントファミリー、画面内にフォントのデザインを描きます。

特定のフォントをポップアップ表示

names(root=None)

names関数は現在使用できるフォントの名前をタプルで取得します。

申し訳ございませんが、引数rootの使い方と意義はよくわかっておりません。

フォントオブジェクトの名前とは、コンストラクタのname引数で指定したものです。

import tkinter as tk
import tkinter.font as tkFont

root = tk.Tk()

font = tk.Font(name="named font")

print(tkFont.names())
# ('systemPushButtonFont', 'systemMenuItemFont', 'systemApplicationFont', 'systemSystemFont', 'systemMenuItemMarkFont', 'TkMenuFont', 'TkDefaultFont', 'named font', 'systemSmallEmphasizedSystemFont', 'systemDetailEmphasizedSystemFont', 'systemMiniSystemFont', 'TkHeadingFont', 'TkTooltipFont', 'systemUtilityWindowTitleFont', 'systemViewsFont', 'systemSmallSystemFont', 'systemMenuTitleFont', 'systemEmphasizedSystemFont', 'TkTextFont', 'systemDetailSystemFont', 'TkCaptionFont', 'systemLabelFont', 'systemAlertHeaderFont', 'systemMenuItemCmdKeyFont', 'TkSmallCaptionFont', 'TkFixedFont', 'systemWindowTitleFont', 'systemToolbarFont', 'TkIconFont')

横スクロールしていただくと、出力結果の中にnamed fontがあるのが確認できます。

すずか
すずか

作ってないフォントの名前もあるけど?

先生
先生

デフォルトで用意されているフォントがあるんですよ。

環境の違いによらず、Tkinterでは標準で下記の名前のフォントが使えます。

名前説明
TkDefaultFontデフォルトのフォント
TkTextFontエントリー・リストボックス等でユーザーが入力する文字列のフォント
TkFixedFont標準の固定幅フォント(各文字が等幅)
TkMenuFontメニュー項目に使用するフォント
TkHeadintFontリストやテーブルの列見出しに使用するフォント
TkCaptionFontウィンドウやダイアログのキャプションバーに使用するフォント
TkSmallCaptionFontサブウィンドウやツールダイアログのキャプションに使用するフォント
TkIconFontアイコンのキャプションに使用するフォント
TkTooltipFontツールチップウィンドウ(一時的な情報ウィンドウ)に使用するフォント
Tkinter標準搭載のフォント名

また、私の環境ではsystemPushButtonFontsystemMenuItemFont等も使えました。

先ほどの出力をご覧いただければと思います。

nametofont(nameroot=None)

nametofont関数は、フォントの名前から実際のフォントオブジェクトを取得します。

既存のフォント設定を参照・操作するのに便利です。

引数は下記の\(2\)つです。

変数名データ型必須 / 任意説明
name文字列必須フォントの名前。
Tkinter標準搭載のフォント・自作のフォントを指定
rootウィジェット任意不明
nametofontメソッドの引数

nametofont関数を利用すると、例えばデフォルトのフォントを一括変更できます。

import tkinter as tk
import tkinter.font as tkFont

root = tk.Tk()

# デフォルトのフォントを取得・変更
default_font = tkFont.nametofont("TkDefaultFont")
default_font.configure(size=50, weight='bold', overstrike=1)

# ラベル
tk.Label(root, text="Hello, World.").pack()

# ボタン
tk.Button(root, text="Hello, World.").pack()

# チェックボタン
tk.Checkbutton(root, text="Hello, World.").pack()

# ラジオボタン
tk.Radiobutton(root, text="Hello, World.").pack()

root.mainloop()

ウィジェットごとにフォント設定をせずとも、意図したフォントになっています。

ラベル・ボタン・チェックボタン・ラジオボタンのデフォルトのフォントを一括変更

もちろんname引数で指定した名前も使えますよ。

font1 = tkFont.Font(name="named font")
font2 = tkFont.nametofont("named font")

まとめ

この記事では、Tkinterのフォントについて解説しました。

最後に軽くまとめて締めましょう。

フォントの変更方法は\(2\)通りありました。

\(2\)つのうち、私はフォントオブジェクトの利用をお勧めします。

その理由は下記です。

フォントオブジェクトの利点

またFontクラスの視点からフォントオブジェクトを眺めると、便利な機能が数多くありましたね。

tkinter.fontモジュールの活用すると、フォントの一覧取得やデフォルトのフォント変更が可能でした。

この記事が少しでも皆様の参考になれば幸いです。

最後までご覧いただき、ありがとうございました。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA