こんにちは、Youtaです。
Tkinterではウィジェットの配置方法がpack, grid, placeの\(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の引数は方位を表す文字です。
英語の各方角の頭文字ですので覚えやすいと思います。
| 文字列 | 寄せる方向 |
|---|---|
tkinter.N または "n" | 上 |
tkinter.E または "e" | 右 |
tkinter.S または "s" | 下 |
tkinter.W または "w" | 左 |
tkinter.NE または "ne" | 右上 |
tkinter.SE または "se" | 右下 |
tkinter.SW または "sw" | 左下 |
tkinter.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_rowconfigure・grid_columnconfigureメソッドです。
構文は下記の通りです。
親ウィジェット.grid_rowconfigure(index, option=value, ...) # indexは行番号
親ウィジェット.grid_columnconfigure(index, option=value, ...) # indexは列番号
ちなみに、以下\(2\)つは同じです。grid_rowconfigure = rowconfiguregrid_columnconfigure = columnconfigure
次章では、メソッドに指定可能なオプションをご紹介します。
オプション
grid_rowconfigure・grid_columnconfigureメソッドのオプション引数をご紹介します。
どちらも効果は同じで、違いは適用範囲が「行か列か」だけです。
| 変数名 | データ型 | 説明 |
|---|---|---|
weight | 整数 | リサイズ時に余白を割り当てる割合 |
grid_rowconfigure・grid_columnconfigureメソッドの引数\(1\)つずつ詳細に見ていきましょう。
weightはリサイズ時に余白を配分する割合です。
値が大きいほど、その列や行により多くのスペースを割り当てます。

余白をweightの比率に配分?
イメージ湧かないわー。

図を使って説明しますね。
例えば、\(0\)列、\(1\)列、\(2\)列のweightをそれぞれ\(1\):\(2\):\(3\)にします。
画面.grid_columnconfigure(0, weight=1) # 0列
画面.grid_columnconfigure(1, weight=2) # 1列
画面.grid_columnconfigure(2, weight=3) # 2列イメージとしては、まず画面の拡大で生じるスペースがweightの比に分割されます。
そして、grid_columnconfigureで指定した比率の余白幅だけ、各列が伸びるというわけです。

grid_rowconfigureで行の高さを調整する際も同様です。

「行高・列幅がweight比になる」のではありません。
「余白をweight比に分けて指定の行・列に割り当てる」のです。
実際にコードを書いて確認してみましょう。
\(0\)行と\(1\)行、\(0\)列と\(1\)列のweightを共に\(1\):\(2\)にします。
import tkinter as tk
root = tk.Tk()
label1 = tk.Label(root, text="Label1", bg="lightblue")
label1.grid(row=0, column=0, sticky="nsew")
label2 = tk.Label(root, text="Label2", bg="lightgreen")
label2.grid(row=0, column=1, sticky="nsew")
label3 = tk.Label(root, text="Label3", bg="lightpink")
label3.grid(row=1, column=0, sticky="nsew")
label4 = tk.Label(root, text="Label4", bg="lightyellow")
label4.grid(row=1, column=1, sticky="nsew")
root.grid_rowconfigure(0, weight=1)
root.grid_rowconfigure(1, weight=2)
root.grid_columnconfigure(0, weight=1)
root.grid_columnconfigure(1, weight=2)
root.mainloop()初期状態です。

まずは縦に引き伸ばしましょう。

次は横に引き伸ばします。

オプションの設定を確認

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には格子を寄せる方向を指定します。

| 文字列 | 寄せる方向 |
|---|---|
tkinter.N または "n" | 上 |
tkinter.E または "e" | 右 |
tkinter.S または "s" | 下 |
tkinter.W または "w" | 左 |
tkinter.NE または "ne" | 右上 |
tkinter.SE または "se" | 右下 |
tkinter.SW または "sw" | 左下 |
tkinter.NW または "nw" | 左上 |
tkinter.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)グリッド上のウィジェットを取得
grid_slavesメソッドは、格子上のウィジェットを取得します。
grid_slavesメソッドの構文です。
親ウィジェット.grid_slaves(row=None, column=None)引数は次の\(2\)つです。
| 変数名 | データ型 | デフォルト | 説明 |
|---|---|---|---|
row | 整数 | すべての行 | 取得したいウィジェットが存在する行番号 |
column | 整数 | すべての列 | 取得したいウィジェットが存在する列番号 |
grid_slavesメソッドの引数grid_slavesメソッドの例をお見せしましょう。
まず、下記の状態を前提とします。
import tkinter as tk
root = tk.Tk()
tk.Label(root).grid(row=0, column=0)
tk.Label(root).grid(row=0, column=1)
tk.Button(root).grid(row=1, column=0)
tk.Button(root).grid(row=1, column=1)ここでgrid_slavesメソッドを試します。
print(root.grid_slaves(row=0, column=0)) # 行・列を指定
# [<tkinter.Label object .!label>]
print(root.grid_slaves(row=0)) # 行のみ指定
# [<tkinter.Label object .!label2>, <tkinter.Label object .!label>]
print(root.grid_slaves(column=0)) # 列のみ指定
# [<tkinter.Button object .!button>, <tkinter.Label object .!label>]
print(root.grid_slaves()) # 指定なし
# [<tkinter.Button object .!button2>, <tkinter.Button object .!button>, <tkinter.Label object .!label2>, <tkinter.Label object .!label>]戻り値のリスト内にはオブジェクト本体があります。
要素を取得した後は、例えばgridやconfigメソッド等で直に操作可能です。
# 1行0列のボタンを取得
button = root.grid_slaves(row=1, column=0)[0]
# 型の確認
print(type(button))
# <class 'tkinter.Button'>
# 操作
button.grid(ipadx=10) # 横幅を調整
button.config(text="Click!") # テキストを表示まとめ
Tkinterのgridメソッドをご紹介しました。
最後に軽く復習してから締めましょう。
gridメソッドは格子状にウィジェットを配置します。
そのオプション引数は計\(10\)個ありました。
またgridメソッドに関連して、下記のような機能を提供するメソッドもありました。
| メソッド名 | 説明 |
|---|---|
grid_rowconfigure | 行ごとに伸縮比率・高さ等の設定を行う。 |
grid_columnconfigure | 列ごとに伸縮比率・高さ等の設定を行う。 |
grid_info | オプションの設定を確認する。 |
grid_anchor | グリッドの寄せ方を制御する。 |
grid_forget | ウィジェットを非表示にする。 オプションは無効化する。 |
grid_remove | ウィジェットを非表示にする。 オプションを保存する。 |
grid_size | グリッドの行数・列数を取得する。 |
grid_slaves | グリッド上のウィジェットを取得する。 |
gridメソッド関連のメソッドこの記事が皆様のお役に立てれば幸いです。
ご覧いただきありがとうございました。

