こんにちは、Youtaです。
Tkinterではウィジェットの配置方法が\(3\)つあります。
今回焦点を当てるのはgrid
メソッドです。
本記事は、grid
メソッドの仕様をすべて解説します。
誰でも必ず理解できるように、豊富な説明と図解を盛り込みました。
早速、grid
メソッドを見ていきましょう!
Contents
grid
メソッド
grid
メソッドは格子状にウィジェットを配置します。
位置を行番号・列番号で指定でき、複雑なレイアウトを簡単に作成するのに役立ちます。
grid
メソッドの構文です。
ウィジェット.grid(オプション=値, ...)
次章では、上記のオプション
に指定できるものをご紹介します。
オプション
grid
メソッドには\(10\)個のオプション引数があります。
row
・column
は、ウィジェットを配置するセルの行番号・列番号です。
行・列共に、番号は\(0\)から始まります。
row
・column
を指定して、任意のセルにウィジェットを置く例です。
import tkinter as tk
root = tk.Tk()
# ラベル1をグリッドの位置(0, 0)に配置
label1 = tk.Label(root, text="Label1", bg="lightblue")
label1.grid(row=0, column=0)
# ラベル2をグリッドの位置(0, 1)に配置
label2 = tk.Label(root, text="Label2", bg="lightgreen")
label2.grid(row=0, column=1)
# ラベル3をグリッドの位置(1, 0)に配置
label3 = tk.Label(root, text="Label3", bg="lightpink")
label3.grid(row=1, column=0)
# ラベル4をグリッドの位置(1, 1)に配置
label4 = tk.Label(root, text="Label4", bg="lightyellow")
label4.grid(row=1, column=1)
root.mainloop()
実行例です。
rowspan
・columnspan
は、ウィジェットを複数の行や列を占めるように配置します。
数値の分だけセルを結合します。
rowspan
・columnspan
を使ってセルを結合する例です。
import tkinter as tk
root = tk.Tk()
# ラベル1をグリッドの位置(0, 0)に配置し、2列にまたがるように指定
label1 = tk.Label(root, text="Label1", bg="lightblue")
label1.grid(row=0, column=0, columnspan=2)
# ラベル2をグリッドの位置(1, 0)に配置し、2行にまたがるように指定
label2 = tk.Label(root, text="Label2", bg="lightgreen")
label2.grid(row=1, column=0, rowspan=2)
# ラベル3をグリッドの位置(1, 1)に配置
label3 = tk.Label(root, text="Label3", bg="lightpink")
label3.grid(row=1, column=1)
# ラベル4をグリッドの位置(2, 1)に配置
label4 = tk.Label(root, text="Label4", bg="lightyellow")
label4.grid(row=2, column=1)
root.mainloop()
実行例です。
padx
・pady
は、ウィジェットの外側の余白(単位: px)を指定します。
CSSのmargin
のようなもので、周囲のウィジェットとの間に隙間を入れます。
基本は整数での指定ですが、タプルもOKです。
より詳細な位置に余白が入ります。
child.grid(
padx=(a, b), # 水平方向の余白: aは左側の余白、bは右側の余白
pady=(c, d), # 垂直方向の余白: cは上側の余白、dは下側の余白
)
後述のipadx
・ipady
はタプルを渡せません。
padx
・pady
でウィジェット間に余白を入れる場合と入れない場合の違いを見ます。
import tkinter as tk
root = tk.Tk()
# ラベル1: 余白なし
label1 = tk.Label(root, text="Label1", bg="lightblue")
label1.grid(row=0, column=0)
# ラベル2: padxあり
label2 = tk.Label(root, text="Label2", bg="lightgreen")
label2.grid(row=0, column=1, padx=20)
# ラベル3: 余白なし
label3 = tk.Label(root, text="Label3", bg="lightpink")
label3.grid(row=1, column=0)
# ラベル4: padyあり
label4 = tk.Label(root, text="Label4", bg="lightyellow")
label4.grid(row=1, column=1, pady=15)
root.mainloop()
実行例です。
ipadx
・ipady
は、ウィジェットの内側の余白(単位: px)を指定します。
CSSのpadding
のようなもので、ウィジェットが占める領域を大きくします。
ipadx
・ipady
で内部に余白を入れる場合と入れない場合の違いを見てみましょう。
import tkinter as tk
root = tk.Tk()
# ラベル1: 余白なし
label1 = tk.Label(root, text="Label1", bg="lightblue")
label1.grid(row=0, column=0)
# ラベル2: ipadxあり
label2 = tk.Label(root, text="Label2", bg="lightgreen")
label2.grid(row=0, column=1, ipadx=20)
# ラベル3: 余白なし
label3 = tk.Label(root, text="Label3", bg="lightpink")
label3.grid(row=1, column=0)
# ラベル4: ipadyあり
label4 = tk.Label(root, text="Label4", bg="lightyellow")
label4.grid(row=1, column=1, ipady=15)
root.mainloop()
実行例です。
sticky
は、ウィジェットをセル内のどの方向に寄せるかを指定します。
sticky
の引数は方位を表す文字です。
英語の各方角の頭文字ですので覚えやすいと思います。
文字列 | 寄せる方向 |
---|---|
tkiner.N または "n" | 上 |
tkiner.E または "e" | 右 |
tkiner.S または "s" | 下 |
tkiner.W または "w" | 左 |
tkiner.NE または "ne" | 右上 |
tkiner.SE または "se" | 右下 |
tkiner.SW または "sw" | 左下 |
tkiner.NW または "nw" | 左上 |
sticky
の引数またsticky
は方角を+
演算子で足せます。
例えばsticky=tk.N+tk.S
で、ウィジェット縦に引き伸ばせます
tk.N+tk.S
の代わりにtk.NS
・"ns"
でも構いません。
(tkinter
をtk
と省略しています。)
同様にsticky=tk.E+tk.W
で、ウィジェット横に引き伸ばせます。
tk.E+tk.W
の代わりにtk.EW
・"ew"
でも構いません。
さらにsticky=tk.N+tk.E+tk.S+tk.W
で、ウィジェットを上下左右に引き伸ばせます。
tk.N+tk.E+tk.S+tk.W
の代わりにtk.NSEW
・"nsew"
でも構いません。
他の合わせ技、例えばsticky=tk.N+tk.S+tk.W
もいけます("nsw"
でも可)。
sticky
を使って、ウィジェットを色々な方角に寄せる例です。
import tkinter as tk
root = tk.Tk()
label1 = tk.Label(root, text="Label1", bg="lightblue")
label1.grid(row=0, column=0, sticky="w") # 左側に配置
canvas = tk.Canvas(root, bg="lightgreen", width=100, height=50)
canvas.grid(row=0, column=1, sticky="e") # 右側に配置
entry = tk.Entry(root)
entry.grid(row=0, column=2, sticky="n") # 上部に配置
button = tk.Button(root, text="Button")
button.grid(row=1, column=0, sticky="s") # 下部に配置
label2 = tk.Label(root, height=3, width=20, text="Label2", bg="lightpink")
label2.grid(row=1, column=1, sticky="nsew") # セル全体に広げる
checkbutton = tk.Checkbutton(root, text="Checkbutton", bg="lightyellow")
checkbutton.grid(row=1, column=2, sticky="ne") # 右上に配置
root.mainloop()
各ウィジェットがバラバラな方向に寄せられていますね。
in_
は、ウィジェットを配置する親コンテナ(ウィジェット)を指定します。
通常、ウィジェットはコンストラクタの第一引数に指定した親に配置されます。
import tkinter as tk
root = tk.Tk()
frame = tk.Frame()
# 親はroot
label = tk.Label(root)
# root(親)にlabelを配置
label.grid(column=0, row=0)
しかし、in_
を使うと後から配置先となる親を変更できるのです。
import tkinter as tk
root = tk.Tk()
frame = tk.Frame()
# 親はroot
label = tk.Label(root)
# frame(新しい親)にlabelを配置
label.grid(column=0, row=0, in_=frame)
配置先を後から変えられるので、レイアウトに自由度が増しますね。
in_
を利用して、ウィジェットの配置位置を切り替える例です。
import tkinter as tk
# ウィジェットの状態を切り替える関数
def toggle():
global is_in_frame
# 現在の状態に応じてadd_label_to_frame()またはremove_label_from_frame()を呼び出す
if is_in_frame:
remove_label_from_frame()
else:
add_label_to_frame()
is_in_frame = not is_in_frame
# labelをlabel_frame内に配置する関数
def add_label_to_frame():
label.grid(in_=label_frame)
# labelをroot内に配置する関数
def remove_label_from_frame():
label.grid(in_=root)
is_in_frame = False
root = tk.Tk()
# ラベルフレームを作成し、配置する
label_frame = tk.LabelFrame(root, text="LabelFrame", width=100, height=100)
label_frame.grid(row=0, column=0, padx=10, pady=10)
# 切り替えボタンをラベルフレームに配置し、toggle関数を紐づける
button = tk.Button(label_frame, text="Button", command=toggle)
button.grid(row=0, column=0, padx=5, pady=5, sticky="nsew")
# メインのラベルを作成し、rootに配置する
label = tk.Label(root, text="Label", bg="lightblue")
label.grid(row=1, column=0, sticky="nsew", padx=5, pady=5)
root.mainloop()
最初、label
はlabel_frame
の外に配置されます。
ボタンを押すと、label
は新しい親label_frame
の中に移動します。
オプションの設定を確認
grid_info
メソッドはgrid
メソッドのオプションの設定を取得します。
grid_info
メソッドの構文です。
子ウィジェット.grid_info()
具体例を示しましょう。
grid_info
メソッドを使うにあたり、下記の状態を前提とします。
import tkinter as tk
root = tk.Tk()
label = tk.Label(root)
label.grid(row=0, column=0)
grid
メソッドの設定を出力してみます。
print(label.grid_info())
# {'in': <tkinter.Tk object .>, 'column': 0, 'row': 0, 'columnspan': 1, 'rowspan': 1, 'ipadx': 0, 'ipady': 0, 'padx': 0, 'pady': 0, 'sticky': ''}
辞書形式で全オプションの設定が取れました。
グリッドの寄せ方を制御
grid_anchor
メソッドは親ウィジェット内での格子の位置を制御します。
grid_anchor
メソッドの構文です。
親ウィジェット.grid_anchor(anchor=None)
引数anchor
には格子を寄せる方向を指定します。
文字列 | 寄せる方向 |
---|---|
tkiner.N または "n" | 上 |
tkiner.E または "e" | 右 |
tkiner.S または "s" | 下 |
tkiner.W または "w" | 左 |
tkiner.NE または "ne" | 右上 |
tkiner.SE または "se" | 右下 |
tkiner.SW または "sw" | 左下 |
tkiner.NW または "nw" | 左上 |
tkiner.CENTER または "c" | 中央 |
grid_anchor
メソッドの引数anchor
の種類sticky
と何が違うの?
sticky
は、セル内でのウィジェットを寄せる方向を決めるのでした。
grid_anchor
メソッドは、コンテナ内での格子を寄せる方向を決めます。
grid_anchor
メソッドを使って、画面内でセル全体を動かす例です。
import tkinter as tk
root = tk.Tk()
root.geometry("250x250") # ウィンドウサイズの設定
# 3行4列のグリッドを作成し、各セルにラベルを配置
for row in range(3):
for col in range(4):
label = tk.Label(root, text=f"({row}, {col})")
label.grid(row=row, column=col)
# 変数varの初期値を"nw"に設定
var = tk.StringVar(value="nw")
# varが変更されると、rootのアンカー位置を更新するコールバックを設定
var.trace_add("write", lambda *args: root.grid_anchor(var.get()))
# 配置する方向のオプションを定義
directions = ("n", "s", "e", "w", "ne", "se", "sw", "nw", "c")
# オプションメニューを作成し、配置の方向を選択
option_menu = tk.OptionMenu(root, var, *directions)
option_menu.grid(column=0, row=row+1, columnspan=col+1)
root.mainloop()
一応コメントを書いていますがStringVar
の設定部分が難しいと思います。
# 変数varの初期値を"nw"に設定
var = tk.StringVar(value="nw")
# varが変更されると、rootのアンカー位置を更新するコールバックを設定
var.trace_add("write", lambda *args: root.grid_anchor(var.get()))
どうしてもわからない方向けに、下記記事にて丁寧に解説しています。
>> StringVarのtrace_addメソッドで、コールバックを自動で呼び出す方法
さて、コードを実行した画面です。
オプションメニューで方向を選びます。
試しに"s"
を選ぶと、グリッド全体が下にシフトするのを確認できます。
ウィジェットを非表示
grid
メソッドで配置したウィジェットを非表示にする方法は\(2\)つあります。
それが、grid_forget
・grid_remove
メソッドです。
構文は下記の通りです。
子ウィジェット.grid_forget()
子ウィジェット.grid_remove()
非表示にしたら戻せないの?
再度grid
メソッドを使うと再表示されます。
grid_forget
・grid_remove
の違い
じゃあ違いは?
grid
メソッドのオプション設定を引き継ぐか否かです。
grid_forget
メソッドは、grid
メソッドのオプション設定を無効化してしまいます。
したがって、再表示の際には再度オプションを設定する必要があります。
# 配置
子ウィジェット.grid(row=0, column=0, padx=10, pady=10, sticky="w")
# 非表示
子ウィジェット.grid_forget()
# 再表示
子ウィジェット.grid(row=0, column=0, padx=10, pady=10, sticky="w")
一方grid_remove
メソッドは、前回指定したオプションの設定を忘れません。
したがって、再表示の際には引数なしでも前回の設定が適用されます。
# 配置
子ウィジェット.grid(row=0, column=0, padx=10, pady=10, sticky="w")
# 非表示
子ウィジェット.grid_remove()
# 再表示
子ウィジェット.grid()
grid_forget
・grid_remove
の具体例
grid_forget
メソッドで、ウィジェットの表示・非表示を切り替える例です。
import tkinter as tk
# ウィジェットの状態を切り替える関数
def toggle():
global is_visible
# 現在の状態に応じてshow()またはhide()を呼び出す
if is_visible:
hide_label()
else:
show_label()
is_visible = not is_visible
# labelを表示する関数
def show_label():
label.grid(row=0, column=0, padx=10, pady=10, sticky="w")
# labelを非表示にする関数
def hide_label():
label.grid_forget()
is_visible = True
root = tk.Tk()
label = tk.Label(root, text="Label", bg="lightblue")
show_label()
# 切り替えボタンを配置し、toggle関数を紐づける
button = tk.Button(root, text="Button", command=toggle)
button.grid(row=1, column=0)
root.mainloop()
最初はlabel
が見えています。
ボタンを押すとlabel
が消えます。
またgrid_remove
メソッドは、再表示の際にオプションの設定を引き継ぐのでしたね。
そのため、show
とhide
関数を次のように書き換えても同じ結果が得られます。
def show_label():
label.grid()
def hide_label():
label.grid_remove()
グリッドの行数・列数を取得
grid_size
メソッドは格子の列数と行数を取得します。
grid_size
メソッドの構文です。
親ウィジェット.grid_size()
戻り値はタプル(列数, 行数)です。
grid_size
メソッドで、グリッドのサイズを取得する例です。
下記状態を前提とします。
import tkinter as tk
root = tk.Tk()
# 3行4列のグリッドを作成し、各セルにラベルを配置
for row in range(3):
for col in range(4):
label = tk.Label(frame, text=f"({row}, {col})")
label.grid(row=row, column=col)
print(root.grid_size())
実行例です。
print(root.grid_size())
# (4, 3)
まとめ
Tkinterのgrid
メソッドをご紹介しました。
最後に軽く復習してから締めましょう。
grid
メソッドは格子状にウィジェットを配置します。
そのオプション引数は計\(10\)個ありました。
またgrid
メソッドに関連して、下記のような機能を提供するメソッドもありました。
メソッド名 | 説明 |
---|---|
grid_info | オプションの設定を確認する。 |
grid_anchor | グリッドの寄せ方を制御する。 |
grid_forget | ウィジェットを非表示にする。 オプションは無効化する。 |
grid_remove | ウィジェットを非表示にする。 オプションを保存する。 |
grid_size | グリッドの行数・列数を取得する。 |
grid
メソッド関連のメソッド
この記事が皆様のお役に立てたら幸いです。
ご覧いただきありがとうございました。