こんにちは、Youtaです。
今回は、Tkinterのフォントについてです。
Tkinterにはテキストを入力・表示するウィジェットが数多くあります。
文字列を扱う場面が多いため、次のように思った方もいるでしょう。
Tkinterのフォントには何があるん?
全フォントを一覧で見られたら便利ですよね。
簡単にコードを組んでみましたよ。
本記事は、フォント操作に長けたtkinter.font
モジュールの機能をすべて解説します。
したがって、Tkinterのフォントに関するお悩みは必ず解消できるはずです。
(上記のフォント一覧出力にも、このモジュールが関与します。)
それでは早速、Tkinterのフォントについて見ていきましょう!
Contents
フォントの変更方法
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()
実行例です。
タプルの代わりに、文字列・リストも使えます。
指定方法は同じです。
# 文字列の場合
label.config(font="Times 20 bold italic underline overstrike")
# リストの場合
label.config(font=["Times", 20, "bold", "italic", "underline", "overstrike"])
次章からは、各パラメータの詳細を説明します。
family
はフォントの字体(フォントファミリー)を表します。
使用可能なfamily
は、 OS に搭載されているフォントに依存します。
family
には何が選べるの?
"Menlo"
や"Times"
等が使用可能です。
後ほど、Tkinterで使えるフォントファミリーの一覧を表示する方法をご紹介します。
注意点としては、\(6\)つのパラメータの中で唯一省略ができません。
じゃあfamily
以外を変えたいときは?
family
にこだわりがなければ、空文字列を指定します。
label.config(font=("", ...))
この場合、デフォルトのフォントが適用されます。
また、無効な文字列を渡した場合もデフォルトのフォントになります。
label.config(font=("Hello, World."))
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)) # デフォルト
続くweight
・slant
等を指定しない場合、size
は省略できます。
この場合、サイズはデフォルト値になります。
# サイズ省略
label.config(font=("Arial"))
weight
・slant
等を指定する場合、size
は省略できないので注意です。
label.config(font=("Arial", "overstrike"))
# _tkinter.TclError: expected integer but got "overstrike"
weight
・slant
・underline
・overstrike
は、フォントの修飾に関連します。
それぞれ太字・斜体・下線・取り消し線の設定です。
太字は"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" ・" |
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.font
はtkFont
と略しています。
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()
実行例です。
さて、フォントの変更方法を\(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
フォントオブジェクトの場合は、未指定のslant
やunderline
等の情報も取れます。
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割はカバーしています。)
それでは早速、下記の項目に沿って解説していきます。
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
と組み合わせて真価を発揮しますよ。
exists
をTrue
にすると、既存のフォントオブジェクトを参照します。
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
を作ります。
name
をoriginal_font
と同一の'original font'
にし、exists
をTrue
にします。
reuse_font = tkFont.Font(name='original font', exists=True)
これにより、reuse_font
はoriginal_font
を参照するようになります。
label1
にoriginal_font
を、label2
にreuse_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\)つのラベルは同一のフォントになっています。
またoriginal_font
でのフォントの変更はreuse_font
で自動更新されます。
試しにmainloop
の直前で、取り消し線をoriginal_font
のみに適用してみましょう。
...
original_font.config(overstrike=1)
root.mainloop()
reuse_font
を適用した下のラベルにも取り消し線が反映されています。
逆もまた然りで、original_font
もreuse_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,
)
じゃあfont
とoptions
両方使うとどうなるの?
両者を同時に使うと、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
メソッドは、フォントの実際の属性を取得します。
属性とはfamily
・size
等の\(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
については情報が少なく、私も完全には理解していません。
上記の情報をもとにすると、次のようなイメージなるかと思います。
displayof
に詳しい方は、ご連絡いただけると幸いです。
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
と同様、キーワード引数で渡します。
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
メソッドはフォントオブジェクトの複製を返します。
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()
どちらのラベルも同じフォントが反映されています。
ただし、複製した方はオリジナルと属性が同じだけのまったくの別物です。
つまり、オリジナルを参照していません。
したがって、先程見たような変更の同期は起こりません。
試しにmainloop
の直前でoriginal_font
の属性を変えてみてください。
...
original_font.config(overstrike=1)
root.mainloop()
original_font
の変更がreplica_font
に反映されないのが確認できます。
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
で指定した項目におけるフォントの測定値を取得します。
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
は行の高さを表し、一般的にはascent
とdescent
の和に一致します。
\(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
は各文字が同一の幅かどうかを示すフラグです。
戻り値はTrue
・False
ではなく\(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
とdisplayof
には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()
そう、冒頭で見た図です。
画像サイズの影響で横が見切れていますが、横にウィンドウを引き伸ばせます。
気になるフォントをクリックすると、ポップアップを表示します。
タイトルにフォントファミリー、画面内にフォントのデザインを描きます。
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 | ツールチップウィンドウ(一時的な情報ウィンドウ)に使用するフォント |
また、私の環境ではsystemPushButtonFont
・systemMenuItemFont
等も使えました。
先ほどの出力をご覧いただければと思います。
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
モジュールの活用すると、フォントの一覧取得やデフォルトのフォント変更が可能でした。
この記事が少しでも皆様の参考になれば幸いです。
最後までご覧いただき、ありがとうございました。