Tkinterの使い方:ウィジェットの配置(pack・grid・place)

ウィジェット配置方法解説ページのアイキャッチ

このページでは Tkinter でのウィジェットの配置について解説します。

Tkinter では「ウィジェットを作成」し、そのウィジェットを親ウィジェットの中(例えばメインウィンドウの中)に「配置」することで、GUI アプリ上にそのウィジェットを表示することができます。

なので「ウィジェットの配置」をしないと、そのウィジェットは画面に表示されません。

また「ウィジェットの配置」をうまく行えれば、アプリの見た目も綺麗になりますし、ユーザーが使用しやすい UI を作成することもできます。

Tkinter では「ウィジェットの配置」を行うためのメソッドとして下記の3つが用意されています。

  • pack
  • grid
  • place

これらは各種類のウィジェットに用意されているメソッドになります。ここからはこの3つのメソッドについて解説していきたいと思います。

pack

pack は親ウィジェット上にウィジェットを詰め込むメソッドです。

pack 使用例

pack を使用してウィジェットを配置するサンプルスクリプトは下記のようになります。pack を最後にまとめて実行していますが、これは今後の説明をしやすくするためです。

各ウィジェットのインスタンス作成後〜メインループ実行前であればどこで実行しても良いです。

pack使用例
# -*- coding:utf-8 -*-
import tkinter

# メインウィンドウ作成
app = tkinter.Tk()
app.geometry("600x400")

# 青色のキャンバス作成
canvas1 = tkinter.Canvas(
	app,
	width=100,
	height=50,
	bg="blue"
)

# 緑色のキャンバス作成
canvas2 = tkinter.Canvas(
	app,
	width=50,
	height=100,
	bg="green"
)

# 1つ目のボタン作成
button1 = tkinter.Button(
	app,
	width=10,
	height=1,
	text="ボタン1"
)

# 2つ目のボタン作成
button2 = tkinter.Button(
	app,
	width=5,
	height=2,
	text="ボタン\n2"
)

# 各ウィジェットの配置
canvas1.pack()
button1.pack()
button2.pack()
canvas2.pack()

# メインループ
app.mainloop()

実行すると下図のようなアプリが起動します。

pack使用例

pack メソッドを実行したウィジェットから順に「上から順に」どんどん親ウィジェット上(メインウィンドウ上)に詰め込まれていく感じで配置されます(インスタンスを生成した順ではないのに注意)。

こんな感じで、ある方向に対してどんどんウィジェットを詰め込んでいくのが pack メソッドになります(どの方向に対して詰め込んでいくかは後述する引数で指定可能)。

引数なしでも実行できる点も pack メソッドの特徴の1つです。

スポンサーリンク

pack の設定(引数)

pack メソッド指定時にキーワード引数を指定することで、様々な設定を行うことができます。

ここでは pack メソッドに指定可能な下記のキーワードと、そのキーワードで設定できる内容を説明していきます。

使用例に関しては、pack 実行部分のみを示しています(他の部分はpack使用例で示したものと同じですので、この点を頭に入れて読んでいただけると助かります)。

主に変更する部分
# 各ウィジェットの配置
canvas1.pack()
button1.pack()
button2.pack()
canvas2.pack()

side

side  の指定により、「どの方向から順に」ウィジェットを詰め込んでいくかを設定することができます。

指定可能パラメータは下記の4つです。

  • tkinter.TOP:上から順に(デフォルト)
  • tkinter.BOTTOM:下から順に
  • tkinter.LEFT:左から順に
  • tkinter.RIGHT:右から順に

例えば下記のように side=tkinter.RIGHT と指定すれば、pack メソッド実行順に「右から順に」ウィジェットが詰め込んでいかれます。

sideの設定例1
# 各ウィジェットの配置
canvas1.pack(
	side=tkinter.RIGHT
)
button1.pack(
	side=tkinter.RIGHT
)
button2.pack(
	side=tkinter.RIGHT
)
canvas2.pack(
	side=tkinter.RIGHT
)

アプリ起動時の画面は下のようになります。

sideの設定例

ウィジェット毎に異なる side 設定を行うことも可能です。

sideの設定例2
# 各ウィジェットの配置
canvas1.pack(
	side=tkinter.RIGHT
)
button1.pack(
	side=tkinter.LEFT
)
button2.pack(
	side=tkinter.BOTTOM
)
canvas2.pack(
	side=tkinter.TOP
)

expand

expand を  True に指定することで、親ウィジェットで使用されていないスペースを利用してウィジェットを配置するスペースを拡大することができます。

例えば先ほどの例だと右から順にウィジェットを並べているので左側にスペースが空いています。

使用していないスペース

このスペースが expand を  True に指定したウィジェットのスペースに割り振られる感じです(そのスペースに対してどこに配置するかは後述する anchor により指定可能です)。

expandをTrueに指定したウィジェットが配置されるスペースが広がる様子

expand の設定例は下記のようになります。

expandの設定例1
# 各ウィジェットの配置
canvas1.pack(
	side=tkinter.RIGHT,
)
button1.pack(
	side=tkinter.RIGHT,
)
button2.pack(
	side=tkinter.RIGHT,
	expand=True
)
canvas2.pack(
	side=tkinter.RIGHT,
)

アプリ起動時の画面は下のようになります。

expandの設定例1

expand=True は複数のウィジェットに指定することも可能です。

expandの設定例2
# 各ウィジェットの配置
canvas1.pack(
	side=tkinter.RIGHT,
	expand=True
)
button1.pack(
	side=tkinter.RIGHT,
)
button2.pack(
	side=tkinter.RIGHT,
	expand=True
)
canvas2.pack(
	side=tkinter.RIGHT,
)

この場合はアプリ起動時の画面は下図のようになります(ボタン1の周りのスペースも広がっているように見えますが、広がっているのは expand=True を設定している青色のキャンバスとボタン2のみです)。

expandの設定例2

anchor

anchor  を指定することで、詰め込んだウィジェットをどの方向に寄せるのかを設定することができます。

下記のようなパラメータを指定することができます。

  • tkinter.N:上方向
  • tkinter.S:下方向
  • tkinter.W:左方向
  • tkinter.E:上方向
  • tkinter.NW:左上方向
  • tkinter.NE:右上方向
  • tkinter.SW:左下方向
  • tkinter.SE:右下方向
  • tkinter.CENTER:中央

上方向と北方向に見立てた方角で考えると覚えやすいです。例えば ↓ こんな感じ

  • 上:北(North)
  • 右上:北東(North East)
  • 左下:南西(South West)

anchor の指定例は下記のようになります。

anchorの設定例
# 各ウィジェットの配置
canvas1.pack(
	side=tkinter.RIGHT,
	expand=True,
	anchor=tkinter.NE
)
button1.pack(
	side=tkinter.RIGHT,
	anchor=tkinter.S
)
button2.pack(
	side=tkinter.RIGHT,
	expand=True,
	anchor=tkinter.SW
)
canvas2.pack(
	side=tkinter.RIGHT,
	anchor=tkinter.CENTER
)

アプリを起動時の画面は下のようになります。

anchorの設定例

イメージとしては次のようにウィジェットが配置されています。

まず side 設定& expand 設定に基づいて各ウィジェットが右から順に詰め込まれていきます。

anchorの動作の様子1

さらにこれらのウィジェットが anchor に従って指定された方向に寄せられ、アプリ起動時の画面通りに配置されるというイメージです。

anchorの動作の様子2

fill

fill を指定することで、ウィジェットを引き伸ばし、与えられたスペースに対していっぱいに広げることができます。

fill に指定できるパラメータは下記の4つになります。

  • tkinter.NONE:引き伸ばししない
  • tkinter.X:横方向に対してのみ引き伸ばす
  • tkinter.Y:縦方向に対してのみ引き伸ばす
  • tkinter.BOTH:縦横両方向に対して引き伸ばす

fill の指定例は下記のようになります。

fillの設定例
# 各ウィジェットの配置
canvas1.pack(
	side=tkinter.RIGHT,
	expand=True,
	fill=tkinter.X
)
button1.pack(
	side=tkinter.RIGHT,
	fill=tkinter.Y
)
button2.pack(
	side=tkinter.RIGHT,
	expand=True,
	fill=tkinter.BOTH
)
canvas2.pack(
	side=tkinter.RIGHT,
	fill=tkinter.NONE
)

スクリプトを実行して起動したアプリの画面は下のようになります。

fillの設定例

下図の fill を指定しない場合の画面と比較すると違いが分かり易いと思います。

例えば、fill=tkinter.X を指定した青いキャンバスは横方向にのみ引き伸ばされ、fill=tkinter.BOTH を指定したボタン2は縦横両方向に対して引き伸ばしてウィジェットが大きくなっていることが確認できます。

anchorの動作の様子1

padx・pady

padx と pady を指定することで、ウィジェットの外側の空白サイズを設定することができます。

padによって空白が付加される様子

pady の設定例は下記のようになります。

padx, padyの設定例
# 各ウィジェットの配置
canvas1.pack(
	pady=100
)
button1.pack()
button2.pack()
canvas2.pack()

スクリプトを実行すると下のような画面のアプリが起動します。pady=100 を指定した青いキャンバスの周り(上下)に 100 px の空白が付加されています。

padx,padyの設定例

ipadx・ipady

padx と pady がウィジェットの外側を設定するのに対し、ipadx と ipady ではウィジェットの内側の空白サイズを設定することができます。つまり、ウィジェットのサイズが大きくなります。

ipadによって空白が付加される様子

ipadx と ipady の設定例は下記のようになります。

ipadx, ipadyの設定例
# 各ウィジェットの配置
canvas1.pack()
button1.pack(
	ipadx=100,
	ipady=100
)
button2.pack()
canvas2.pack()

スクリプトを実行すると下のような画面のアプリが起動します。ipadx=100 と ipady=100 を指定したボタン1の内側(上下左右)に 100 px の空白が付加されています。

ipadx,ipadyの設定例

beforeafter

通常 pack メソッドでは実行した順番で親ウィジェットに対して詰め込まれていきますが、  beforeafter を指定することで、 この詰め込まれる順番を制御することができます(正確には詰め込まれる順番を制御したようにウィジェットが配置されます)。

beforeafter には他のウィジェットのインスタンスを指定し、これにより pack メソッドを実行したウィジェットが詰め込まれる順番が下記のように変わります。

  • before :指定したウィジェットの前に pack メソッドを実行したウィジェットが詰め込まれる
  • after :指定したウィジェットの後に pack メソッドを実行したウィジェットが詰め込まれる

before と after の設定例は下記のようになります。

before, afterの設定例
# 各ウィジェットの配置
canvas1.pack()
button1.pack()
button2.pack(
	after=canvas1
)
canvas2.pack(
	before=canvas1
)

スクリプトを実行すると下のような画面のアプリが起動します。

before, afterの設定例

pack メソッドを実行する順番は canvas1(青のキャンバス)→ button1(ボタン1)→ button2(ボタン2)→ canvas2(緑のキャンバス)ですが、canvas2(緑のキャンバス)の pack 実行時に before=canvas1 を指定しているため、canvas2(緑のキャンバスは canvas1(青のキャンバス)よりも上側に配置されています。

同様に button2(ボタン2)の pack 実行時に after=canvas1 を指定しているため、button2(ボタン2)は canvas1(青のキャンバス)のすぐ下に配置されています。

in_

in_  を指定することで、ウィジェットの配置先となる親ウィジェットを設定することができます。

指定しない場合はウィジェットのインスタンス生成時に指定した親ウィジェットに対して配置されます。

pack 関連のメソッド

pack 関連のメソッドも紹介しておきます。

pack_info

pack_info は実行したウィジェットに対する pack の情報を取得するメソッドです。

要は pack メソッド実行時に設定した情報(辞書)を取得することができます。

pack_infoの使用例
# button1はボタンのインスタンス
info = button1.pack_info()

pack_forget

pack_forget は実行したウィジェットを画面から消すメソッドです。

画面からは消えますが、そのウィジェットのインスタンスが消えるわけではないので再度 pack メソッド等で画面に表示することができます(ただし前回指定した設定は忘れ去られているので再度設定が必要)。

pack_forgetの使用例
# button1はボタンのインスタンス
button1.pack_forget()

pack を使用するメリット・デメリット

引数なしでも実行できるのでとにかく簡単に使用できます。私も一番使用するのがこの packです。

とりあえずアプリの動作確認を行いたいだけであれば pack() さえ実行しておけば良いです。

ただし、pack はウィジェットを1次元に配置することを前提としたメソッドなので、ウィジェットの2次元的な配置には pack は向きません。

スポンサーリンク

grid

grid は親ウィジェットを2次元的に複数のセルに分割し、各セルにウィジェットを配置するメソッドです。簡単にウィジェットを2次元的に配列できるところが特徴です。

grid 使用例

grid を使用してウィジェットを配置するサンプルスクリプトは下記のようになります。grid を最後にまとめて実行していますが、これは今後の説明をしやすくするためです。

各ウィジェットのインスタンス作成後〜メインループ実行前であればどこで実行しても良いです。

grid使用例
# -*- coding:utf-8 -*-
import tkinter

# メインウィンドウ作成
app = tkinter.Tk()
app.geometry("600x400")

# 青色のキャンバス作成
canvas1 = tkinter.Canvas(
	app,
	width=300,
	height=100,
	bg="blue"
)

# 緑色のキャンバス作成
canvas2 = tkinter.Canvas(
	app,
	width=100,
	height=200,
	bg="green"
)

# 1つ目のボタン作成
button1 = tkinter.Button(
	app,
	width=10,
	height=1,
	text="ボタン1"
)

# 2つ目のボタン作成
button2 = tkinter.Button(
	app,
	width=5,
	height=2,
	text="ボタン\n2"
)

# ウィジェットの配置
canvas1.grid(
	column=0,
	row=0
)

button1.grid(
	column=1,
	row=0,
)

button2.grid(
	column=0,
	row=1
)

canvas2.grid(
	column=1,
	row=1
)

# メインループ
app.mainloop()

実行すると下図のようなアプリが起動します。

gridの使用例

grid を実行することで親ウィジェットを二次元的にセルに分割し、そのセル内にウィジェットを配置することができます。

上記のスクリプトの場合は、メインウィンドウを下のように 2 x 2 の4つのセルに分割し、さらにそれぞれのセルにウィジェットを配置しています。

gridによりセルに分割される様子

grid の設定(引数)

grid メソッド指定時にキーワード引数を指定することで、様々な設定を行うことができます。

ここでは grid メソッドに指定可能な下記のキーワードと、そのキーワードで設定できる内容を説明していきます。

使用例に関しては、grid 実行部分のみを示しています(他の部分はgrid使用例で示したものと同じですので、この点を頭に入れて読んでいただけると助かります)。

主に変更する部分
# ウィジェットの配置
canvas1.grid(
	column=0,
	row=0
)

button1.grid(
	column=1,
	row=0,
)

button2.grid(
	column=0,
	row=1,
	sticky=tkinter.NSEW
)

canvas2.grid(
	column=1,
	row=1
)

columnrow

columnrow を指定することで、grid を実行したウィジェットを親ウィジェットのどのセルにウィジェットを配置するかを設定することができます。columnrow は “0” 以上の整数を指定します。

columnとrow指定によってウィジェットが配置される様子

また、grid メソッド実行時に指定した columnrow の最大値に応じてセルが自動的に分割されます。

具体的には、column で指定した値の中の最大値 +1 の列数に、row  で指定した値の中の最大値 +1 の行数に分割されます。

この時、各セルの幅はそのセルの列の中に配置されるウィジェットの中で一番幅が大きいサイズに、各セルの高さはそのセルの行の中に配置されるウィジェットの中で一番高さがが大きいサイズに自動的に調整されます。

各セルのサイズ

ですので、ウィジェットが配置されていないセルのサイズは 0 x 0 になり、見た目的には無い物として扱われます。

各セル全てに配置する必要がなく、下記スクリプトのように columnrow を飛び飛びに指定しても OK です。

column,rowの設定例
# ウィジェットの配置
canvas1.grid(
	column=0,
	row=0
)

button1.grid(
	column=2,
	row=0,
)

button2.grid(
	column=1,
	row=1
)

canvas2.grid(
	column=3,
	row=1
)

このスクリプトを実行して起動するアプリの画面は下のようになります。

columnとrowを飛び飛びで指定した時の画面

sticky

stickcy を指定することで、セル内のどの方向にウィジェットを寄せて配置するかを設定することができます。

pack で紹介した anchor 同様に下記のようなパラメータを指定することができます。

  • tkinter.N:上方向
  • tkinter.S:下方向
  • tkinter.W:左方向
  • tkinter.E:上方向
  • tkinter.NW:左上方向
  • tkinter.NE:右上方向
  • tkinter.SW:左下方向
  • tkinter.SE:右下方向
  • tkinter.CENTER:中央

さらに stickcy  には下記のパラメータについても指定可能です。

  • tkinter.NSEW:上下左右

また、stickcy には + 演算子を用いて複数の方向を指定することが可能であり、複数指定した場合は各方向に対してウィジェットを引き伸ばすことができます。

stickcy に1方向だけ指定する場合の設定例は下記のようになります。

stickyの設定例1
# ウィジェットの配置
canvas1.grid(
	column=0,
	row=0
)

button1.grid(
	column=1,
	row=0,
)

button2.grid(
	column=0,
	row=1,
	sticky=tkinter.NE
)

canvas2.grid(
	column=1,
	row=1
)

この場合、アプリを起動すると下のような画面になります。sticky=tkinter.NE を指定したボタン2が右上方向に寄せられていることが確認できると思います。

stickyの設定例1

stickcy に複数の方向を指定する場合の設定例は下記のようになります。

stickyの設定例2
# ウィジェットの配置
canvas1.grid(
	column=0,
	row=0
)

button1.grid(
	column=1,
	row=0,
)

button2.grid(
	column=0,
	row=1,
	sticky=tkinter.NE+tkinter.NW+tkinter.S
)

canvas2.grid(
	column=1,
	row=1
)

この場合、アプリを起動すると下のような画面になります。sticky=tkinter.NE+tkinter.NW+tkinter.S を指定したボタン2がセル内に目一杯に広がっていることが確認できると思います。

stickyの設定例2

この時の stickcy の効果を説明しておきます。まずウィジェットは右上方向(tkinter.NE)に配置されます。

stickyの効果1

さらにそのウィジェットが左上方向(tkinter.NW)に引き伸ばされます。

stickyの効果2

最後にその引き伸ばされたウィジェットが下方向(tkinter.S)に引き伸ばされ、これによりセル内全体にウィジェットが拡大されたことになります。

stickyの効果3

sticky に tkinter.NSEW を指定した場合はセル内の全方向にウィジェットが広がることになります。

columnspanrowspan

columnspanrowspan を指定することで、複数のセルにまたがってウィジェットを配置することができます。それぞれ正の整数を指定します(0 はダメです)。

columnspanを指定した場合、ウィジェットは column で指定した列から columnspan 列分にまたがって配置されます。

また rowspanを指定した場合、ウィジェットは row で指定した行から columnspan 行分にまたがって配置されます。

columnspan の設定例は下記のようになります。

columnspanの設定例
# -*- coding:utf-8 -*-
import tkinter

# メインウィンドウ作成
app = tkinter.Tk()
app.geometry("200x100")


# 1つ目のボタン作成
button1 = tkinter.Button(
	app,
	width=10,
	height=1,
	text="ボタン1"
)

# 2つ目のボタン作成
button2 = tkinter.Button(
	app,
	width=10,
	height=1,
	text="ボタン2"
)

# 3つ目のボタン作成
button3 = tkinter.Button(
	app,
	width=10,
	height=1,
	text="ボタン3"
)

# ウィジェットの配置
button1.grid(
	column=0,
	columnspan=2,
	row=0,
)

button2.grid(
	column=0,
	row=1,
)

button3.grid(
	column=1,
	row=1,
)


# メインループ
app.mainloop()

アプリ起動時の画面は下の図のようになります。

columnspanの設定例

columnspan を指定しない場合はボタン1はボタン2の真上(つまり column=0row=0)に配置されることになります。

しかし、上のスクリプトではボタン1に columnspan=2 を指定しているので column=0 と column=1 の2列分にまたがって配置され、上の図のようなウィジェットの配置になっています。

こんな感じで columnspan を指定すれば、セルとセルの切れ目の部分にもウィジェットを配置することができます。

また、先ほど説明した sticky を指定すれば、ウィジェットを複数の列全体に広げて配置するようなことも可能です。

複数の列にまたがってウィジェットを配置したい場合はrownspan を指定してください。

padxpadyipadxipady

padxpadyipadxipady を grid メソッドに指定することも可能です。

指定の仕方や効果に関しては pack で紹介したものと同様ですので、説明は省略します。

in_

in_ についても pack で紹介したものと同様ですので省略します。

スポンサーリンク

grid 関連のメソッド

grid 関連のメソッドも紹介しておきます。

grid_slaves

コレは便利なので覚えておいた方が良いです!

grid_slaves は実行したウィジェット上に grid で配置されているウィジェットのリストを取得するメソッドです。

引数の columnrow により、どこに配置したウィジェットのリストを取得したいかを指定することができます。

例えば下記のようにして grid_slaves を実行することで、frame1 上の column=2, row=1 に配置されたウィジェットのリストを取得することができます。

grid_slavesの使用例
import tkinter

def button_click():
    global frame1

    # grid_slavesframe1上の(2, 1)に
    # 配置されているウィジェットのリスト取得
    widgets = frame1.grid_slaves(column=2, row=1)
    
    # リストの先頭のウィジェットの背景色変更
    widgets[0].config(
        bg="#FF0000"
    )

app = tkinter.Tk()

# フレーム作成と配置
frame1 = tkinter.Frame(
    app
)
frame1.pack()

# ボタン作成と配置
button1 = tkinter.Button(
    app,
    text="ボタン",
    command=button_click
)
button1.pack()

# ラベル作成と配置
for j in range(5):
    for i in range(3):
        # 3x5のラベルを作成してgridで配置
        label = tkinter.Label(
            frame1,
            text="test"
        )
        label.grid(column=i, row=j)

app.mainloop()

取得したリストからウィジェットを取り出して設定変更などを行うことも可能です。上の例だと背景色を変更しています。

取得できるのはリストである点に注意です。1つしかウィジェットが配置されていない場合でも、要素番号を指定するようにしましょう。

grid_info

grid_info は実行したウィジェットに対する grid の情報を取得するメソッドです。

要は grid メソッド実行時に設定した情報(辞書形式)を取得することができます。

grid_infoの使用例
# button1はボタンのインスタンス
info = button1.grid_info()

grid_forget

grid_forget は実行したウィジェットを画面から消すメソッドです。

画面からは消えますが、そのウィジェットのインスタンスが消えるわけではないので再度 grid メソッド等で画面に表示することができます(ただし前回指定した設定は忘れ去られているので再度設定が必要)。

grid_forgetの使用例
# button1はボタンのインスタンス
button1.grid_forget()

grid_remove

grid_remove は grid_forget 同様に実行したウィジェットを画面から消すメソッドです。

が、grid_remove はgrid_forget とは違って前回 grid メソッド実行時に指定した設定が保持されているので、再度 grid メソッドを実行すれば(引数なしで)前回と同じ設定で画面に配置することができます。

grid_removeの使用例
# button1はボタンのインスタンス
button1.grid_remove()

grid_size

grid_size はセルの数を返却するメソッドです。具体的にはセルの行数と列数を返却します。ウィジェットの配置先となる親ウィジェットで実行します。

grid_sizeの使用例
# appは親ウィジェットのインスタンス
app.grid_size()

grid_anchor

grid_anchor は分割されたセルをどの方向に寄せるかを指定するメソッドです。

packanchor指定で示した9つのパラメータを指定することができます。

  • tkinter.N:上方向
  • tkinter.S:下方向
  • tkinter.W:左方向
  • tkinter.E:上方向
  • tkinter.NW:左上方向
  • tkinter.NE:右上方向
  • tkinter.SW:左下方向
  • tkinter.SE:右下方向
  • tkinter.CENTER:中央

grid_anchor はウィジェットの配置先となる親ウィジェットで実行します。

grid_anchorの使用例
# appは親ウィジェットのインスタンス
app.grid_anchor(tkinter.CENTER)

grid_columnconfigure

grid_columnconfigure は列ごとにセルの設定を行うメソッドです。ウィジェットの配置先となる親ウィジェットで実行します。

第1引数には列番号grid メソッド実行時に column で指定した値)を、第2引数以降は、下記に記載した設定をキーワード引数により指定します。

  • weight
    • 指定した列のセルをウィンドウの余白量に応じて横方向に広げるかどうかの設定
      • 0:広げない
      • 1 以上:広げる(値に応じて広がる割合が増加)
  • minsize
    • 指定した列のセルの横方向最小サイズ(px)
  • pad
    • 指定した列のセルに対する横方向の余白追加量(px)

ちょっと分かりにくい weight 設定について、下記スクリプトを基に説明したいと思います。

grid_columnfigureなし
# -*- coding:utf-8 -*-
import tkinter

# メインウィンドウ作成
app = tkinter.Tk()
app.geometry("600x400")


# 青色のキャンバス作成
canvas1 = tkinter.Canvas(
	app,
	width=100,
	height=100,
	bg="blue"
)

# 緑色のキャンバス作成
canvas2 = tkinter.Canvas(
	app,
	width=100,
	height=100,
	bg="green"
)

# 赤色のキャンバス作成
canvas3 = tkinter.Canvas(
	app,
	width=100,
	height=100,
	bg="red"
)

# 紫色のキャンバス作成
canvas4 = tkinter.Canvas(
	app,
	width=100,
	height=100,
	bg="purple"
)

# ウィジェットの配置
canvas1.grid(
	column=0,
	row=0,
	sticky=tkinter.NSEW
)
canvas2.grid(
	column=1,
	row=0,
	sticky=tkinter.NSEW
)
canvas3.grid(
	column=0,
	row=1,
	sticky=tkinter.NSEW
)
canvas4.grid(
	column=1,
	row=1,
	sticky=tkinter.NSEW
)

# メインループ
app.mainloop()

実行して起動するアプリの画面は下の図のようになります。

grid_columnconfigureの説明1

4つのセルに分割され、各ウィジェットに sticky=tkinter.NSEW をしているのでセルいっぱいにウィジェットが引き伸ばされるため、上の図のようなアプリ画面になっています。

続いて下記を mainloop 実行前に追加して grid_columnconfigure により column=0 の列に weight=1 を設定します。

weightの使用例1
# appはメインウィンドウのインスタンス
app.grid_columnconfigure(0, weight=1)

これを追加することで、アプリの起動画面は下の図のように変わります。もともとメインウィンドウの右側にあった余白量の分、column=0 の列のセルの横方向のサイズが広がっていることが確認できると思います。

grid_columnconfigureの説明2

column=1 の列のセルの横方向のサイズが変化していないのは weight を設定していないためです(縦方向のサイズを変化させたい場合は次に説明する grid_rowconfigure メソッドを使用します)。

今度は下記のように column=1 に対して weight=2 を設定してみましょう。

weightの使用例2
# appはメインウィンドウのインスタンス
app.grid_columnconfigure(0, weight=1)
app.grid_columnconfigure(1, weight=2)

この時のアプリの画面は下の図のようになります。

grid_columnconfigureの説明3

今度は column=1 の列のセルも広がっていることが確認できると思います。column=1 の方がセルが大きくなっているのは、weight で指定した値が column=0 よりも大きいためです。

こんな感じで weight の比率に応じて、その列のセルに与えられる親ウィジェットの余白が増えることになります。

また親ウィジェットの余白量が変われば weight の比率に応じて各列のサイズも変わります。下の図は column=0 と column=1 両方に対して weight=1 を設定したアプリのメインウィンドウを変化した時のアニメになります。

grid_columnconfigureの説明4

こんな感じで weight を利用することで、ウィンドウのリサイズ時にもレイアウトの崩れないウィジェットの配置が可能になります。

grid_rowconfigure

grid_rowconfigure は行ごとにセルの設定を行うメソッドです。

grid_columnconfigure と設定する方向が異なるだけで使い方等は同じなので説明は省略します。

grid_bbox(bbox)

grid_bbox は引数で指定したセルの親ウィジェット上の左上座標とサイズを返却するメソッドです。ウィジェットの配置先となる親ウィジェットで実行します。

grid_bbox の返却値は (x, y , width, height) の形式のタプルとなります。

  • x:指定したセルの横方向の座標(親ウィジェット上での座標)
  • y:指定したセルの縦方向の座標(親ウィジェット上での座標)
  • width:指定したセルの横方向のサイズ
  • height:指定したセルの縦方向のサイズ

grid_bbox の定義は下記のようになっており、最大4つの引数を指定することができます。

grid_bboxの定義
grid_bbox(self, column=None, row=None, col2=None, row2=None)

1つのセルの座標とサイズを取得したい場合は columnrow の2つを指定します。これにより指定した columnrow の位置のセルの左上座標とサイズが返却されます。

columnrowcol2row2 の4つの引数を指定することで、複数のセルを指定することも可能です。

この場合は column から col2 の行および row から row2 の列の範囲のセルを合体させた時の座標とサイズを取得することができます。

grid_bboxの説明図

また、引数を指定しなかった場合は、全ての行と全ての行の範囲のセルを合体させた時の座標とサイズを取得することができます。

ただし grid_bbox はウィジェットの配置が完了し、それが画面に反映された後でなければうまく情報が取得できない点に注意してください。

基本的にウィジェットの配置等が画面に反映されるのは mainloop 実行中や update メソッド実行後になります。このあたりは下記のメインウィンドウのページで解説しているので詳しく知りたい方は読んでみてください。

メインウィンドウ作成解説ページのアイキャッチTkinterの使い方:Tk クラスでメインウィンドウを作成

したがって、mainloop 実行前は update メソッド実行しない限りは grid_bbox を実行してもうまく情報が取得できません。おそらく取得できるデータは (0, 0, 0, 0) になると思います。

grid を使用するメリット・デメリット

簡単にウィジェットを2次元的に配置できる点が良いです。

基本的に GUI アプリではウィジェットを2次元的に配列することになりますので、一番使われている方法ではないかと思います。

ウィジェットの数が多くてもそこまで負荷は増えません。

大雑把にウィジェットを配置する点では最強だと思いますが、細かくウィジェットの位置を指定したい場合は次に説明する place の方が向いていると思います。

place

place は親ウィジェット上の座標を指定して、その座標にウィジェットを配置するメソッドです。

スポンサーリンク

place 使用例

place を使用してウィジェットを配置するサンプルスクリプトは下記のようになります。place を最後にまとめて実行していますが、これは今後の説明をしやすくするためです。

各ウィジェットのインスタンス作成後〜メインループ実行前であればどこで実行しても良いです。

place使用例
# -*- coding:utf-8 -*-
import tkinter

# メインウィンドウ作成
app = tkinter.Tk()
app.geometry("600x400")

# 青色のキャンバス作成
canvas1 = tkinter.Canvas(
	app,
	width=100,
	height=50,
	bg="blue"
)

# 緑色のキャンバス作成
canvas2 = tkinter.Canvas(
	app,
	width=50,
	height=100,
	bg="green"
)

# 1つ目のボタン作成
button1 = tkinter.Button(
	app,
	width=10,
	height=1,
	text="ボタン1"
)

# 2つ目のボタン作成
button2 = tkinter.Button(
	app,
	width=5,
	height=2,
	text="ボタン\n2"
)

# 各ウィジェットの配置
canvas1.place(
	x=100,
	y=100
)
button1.place(
	x=400,
	y=100
)
button2.place(
	x=100,
	y=200
)
canvas2.place(
	x=400,
	y=200
)

# メインループ
app.mainloop()

実行すると下図のようなアプリが起動します。

placeの使用例

place は考え方は最もシンプルで、place を実行することで、引数で指定した(x , y) 座標にウィジェットが配置されます。

placeでの座標指定

原点は親ウィジェットの左上端で、x 軸の正方向は右、y 軸の正方向は下になります。

place の設定(引数)

place メソッド指定時にキーワード引数を指定することで、様々な設定を行うことができます。

ここでは place メソッドに指定可能な下記キーワードと、そのキーワードで設定できる内容を説明していきます。

使用例に関しては、place 実行部分のみを示しています(他の部分はplace使用例で示したものと同じですので、この点を頭に入れて読んでいただけると助かります)。

主に変更する部分
# 各ウィジェットの配置
canvas1.place(
	x=100,
	y=100
)
button1.place(
	x=400,
	y=100
)
button2.place(
	x=100,
	y=200
)
canvas2.place(
	x=400,
	y=200
)

xy

xy を指定することで、ウィジェットを配置する座標を設定することができます。

ウィジェットの左上を基準に、親ウィジェットの(x, y)座標にウィジェットが配置されます(どこを基準にするかは次に説明する anchor で指定可能です)。

anchor

anchor を指定することで、ウィジェット配置時のウィジェットの基準位置を指定することができます。

anchor に指定できるパラメータは Packanchor で示した9種類と同じになります(デフォルトは tkinter.NW)。

例えば anchor=tkinter.CENTER を指定すれば、親ウィジェットの(x, y)座標にウィジェットの中心が来るようにウィジェットの配置が行われます。

anchor の設定例は下記のようになります。

anchorの設定例
# 各ウィジェットの配置
canvas1.place(
	x=100,
	y=100,
	anchor=tkinter.CENTER
)
button1.place(
	x=400,
	y=100,
	anchor=tkinter.NW
)
button2.place(
	x=100,
	y=200,
	anchor=tkinter.S
)
canvas2.place(
	x=400,
	y=200,
	anchor=tkinter.SE
)

スクリプトを実行して起動するアプリの画面は下図のようになります。

anchorの設定例

widthheight

widthheight を指定することで、ウィジェットの幅と高さを指定することができます。

ピクセル単位で指定します。

place メソッドに widthheight を指定することで、ウィジェットのインスタンス作成時に指定した widthheight は無視されるので注意しましょう。

widthheight の設定例は下記のようになります。

width, heightの設定例
# 各ウィジェットの配置
canvas1.place(
	x=100,
	y=100,
	width=100,
	height=100
)
button1.place(
	x=400,
	y=100,
	width=100,
	height=100
)
button2.place(
	x=100,
	y=200,
	width=100,
	height=100
)
canvas2.place(
	x=400,
	y=200,
	width=100,
	height=100
)

スクリプトを実行して起動するアプリの画面は下図のようになります。

各ウィジェットの幅と高さは、ウィジェットインスタンス時に指定した widthheight ではなく、place メソッド実行時に指定した widthheight になってることも確認できると思います。

width,heightの設定例

relxrely

relxrely は xy 同様にウィジェットを配置する座標を指定する引数になります。

ですが、 xy は親ウィジェット上の座標を単純に指定するのに対し、relxrely は親ウィジェットの幅と高さを “1” とした時の相対位置を指定する点が異なります。

相対サイズの説明図

例えば親ウィジェットの中心は relx=0.5rely=0.5 になります。

指定できる値は 0.01.0 になります。

relxrely の設定例は下記のようになります。

relx, relyの設定例
# 各ウィジェットの配置
canvas1.place(
	relx=0.1,
	rely=0.1
)
button1.place(
	relx=0.6,
	rely=0.1
)
button2.place(
	relx=0.1,
	rely=0.6
)
canvas2.place(
	relx=0.6,
	rely=0.6
)

スクリプトを実行して起動するアプリの画面は下図のようになります。

relx,relyの設定例

前述の通り、relxrely は親ウィジェットの幅と高さを “1” とした時の相対位置となりますので、親ウィジェットのサイズが変わればそれに応じてウィジェットの配置位置も変化する点もポイントです。

relx,relyの設定例

relwidthrelheight

relwidthrelheight は widthheight 同様にウィジェットの幅と高さを指定する引数になります。

ですが、 widthheight はピクセル単位で指定するするのに対し、relwidthrelheight は親ウィジェットの幅と高さを “1” とした時の相対的なサイズを指定する点が異なります。

相対サイズの説明図

例えば親ウィジェットの幅と高さそれぞれの半分のサイズを表す場合は relwidth=0.5relheight=0.5 になります。

指定できる値は 0.01.0 になります。

relwidthrelheight の設定例は下記のようになります。

relwidth, relheightの設定例
# 各ウィジェットの配置
canvas1.place(
	relx=0.1,
	rely=0.1,
	relwidth=0.3,
	relheight=0.3
)
button1.place(
	relx=0.6,
	rely=0.1,
	relwidth=0.3,
	relheight=0.3
)
button2.place(
	relx=0.1,
	rely=0.6,
	relwidth=0.3,
	relheight=0.3
)
canvas2.place(
	relx=0.6,
	rely=0.6,
	relwidth=0.3,
	relheight=0.3
)

スクリプトを実行して起動するアプリの画面は下図のようになります。

relwidth,relheightの設定例

前述の通り、relwidthrelheight は親ウィジェットの幅と高さを “1” とした時の相対サイズとなりますので、親ウィジェットのサイズが変わればそれに応じてウィジェットの幅と高さも変化する点もポイントです。

上記スクリプトではウィジェットの位置も相対位置である relxrely を指定しているため、ウィジェットの位置も幅・高さも親ウィジェットのサイズに応じて変化します。

なので親ウィジェットのサイズ変更によるレイアウトの崩れはありません(文字のサイズなどのウィジェットの中身は別途リサイズ対応が必要)。

relwidth,relheightの設定例

bordermode

bordermode を指定することで、ウィジェットを配置する親ウィジェットの基準位置、つまり(0, 0)座標を「外枠の外側」にするか「外枠の内側」にするかを指定することができます。

bordermode に指定するパラメータは下記の2つになります。

  • tkinter.INSIDE:ウィジェットを配置する親ウィジェットの基準位置を「外枠の内側」とする
  • tkinter.OUTSIDE:ウィジェットを配置する親ウィジェットの基準位置を「外枠の外側」とする

bordermode の設定例は下記のようになります(今回の例は他の例と作成するウィジェットが異なるのでスクリプト全体を載せています)。

bordermodeの設定例
# -*- coding:utf-8 -*-
import tkinter

# メインウィンドウ作成
app = tkinter.Tk()
app.geometry("600x400")

# フレーム作成
frame1 = tkinter.Frame(
	app,
	width=600,
	height=400,
	borderwidth=30,
	bg="yellow",
	relief=tkinter.SUNKEN
)

# 緑色のキャンバス作成
canvas1 = tkinter.Canvas(
	frame1,
	width=50,
	height=100,
	bg="green"
)

frame1.pack()

# 各ウィジェットの配置
canvas1.place(
	relx=0,
	rely=0,
	bordermode=tkinter.INSIDE
)


# メインループ
app.mainloop()

緑色のキャンバスの place 実行時に bordermode=tkinter.INSIDE を指定しているので、親ウィジェットの外枠の内側を基準位置として指定した位置(0, 0)に配置されていることが確認できると思います。

bordermdoeの設定例1

bordermode の指定部分のみを bordermode=tkinter.OUTSIDE に変更した場合のアプリ画面は下のようになります。

bordermdoeの設定例2

今度は親ウィジェットの外枠の外側を基準位置として指定した位置(0, 0)に配置されていることが確認できると思います。

in_

in_  を指定することで、ウィジェットの配置先となる親ウィジェットを設定することができます。

place 関連のメソッド

place 関連のメソッドも紹介しておきます。

place_info

place_info は実行したウィジェットに対する place の情報を取得するメソッドです。

要は place メソッド実行時に設定した情報(辞書形式)を取得することができます。

place_infoの使用例
# button1はボタンのインスタンス
info = button1.place_info()

place_forget

place_forget は実行したウィジェットを画面から消すメソッドです。

画面からは消えますが、そのウィジェットのインスタンスが消えるわけではないので再度 place メソッド等で画面に表示することができます(ただし前回指定した設定は忘れ去られているので再度設定が必要)。

place_forgetの使用例
# button1はボタンのインスタンス
button1.place_forget()

スポンサーリンク

place を使用するメリット・デメリット

考え方は一番シンプルだと思います。私はこの方法が一番好きですね。一番ウィジェットの位置を細かく指定できる方法でもあります。

ただし座標を指定する必要があるので座標を計算するのが大変です。

特にウィジェットの数が多ければ多いほど座標を計算する負荷が増えます。

まとめ

このページでは Tkinter でのウィジェットの配置について説明しました。

配置するために利用するメソッドには下記の3種類があります。それぞれ特徴が異なるのでこの特徴だけはしっかり覚えておきましょう!

  • pack:ウィジェットをある方向にどんどん詰め込む
  • grid:2次元的に親ウィジェットをセルに分割し、セル内にウィジェットを配置する
  • place:配置する座標を指定してウィジェットを配置する

用途としては、とにかくウィジェットを配置したいだけなら pack、簡単にウィジェットを2次元的に配置したいなら grid、座標計算が得意な人は place といった感じかなあと思います。

また、各メソッド実行時には様々な引数が指定可能であり、細やかな設定を行うことができます。各メソッドに対して指定可能な全引数をこのページでまとめていますので、困ったときに参照していただければと思います!

コメントを残す

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