このページでは Tkinter でのウィジェットの配置について解説します。
Tkinter では「ウィジェットを作成」し、そのウィジェットを親ウィジェットの中(例えばメインウィンドウの中)に「配置」することで、GUI アプリ上にそのウィジェットを表示することができます。
なので「ウィジェットの配置」をしないと、そのウィジェットは画面に表示されません。
また「ウィジェットの配置」をうまく行えれば、アプリの見た目も綺麗になりますし、ユーザーが使用しやすい UI を作成することもできます。
Tkinter では「ウィジェットの配置」を行うためのメソッドとして下記の3つが用意されています。
pack
grid
place
これらは各種類のウィジェットに用意されているメソッドになります。ここからはこの3つのメソッドについて解説していきたいと思います。
Contents
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
メソッドの特徴の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
メソッド実行順に「右から順に」ウィジェットが詰め込んでいかれます。
# 各ウィジェットの配置
canvas1.pack(
side=tkinter.RIGHT
)
button1.pack(
side=tkinter.RIGHT
)
button2.pack(
side=tkinter.RIGHT
)
canvas2.pack(
side=tkinter.RIGHT
)
アプリ起動時の画面は下のようになります。
ウィジェット毎に異なる side
設定を行うことも可能です。
# 各ウィジェットの配置
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
の設定例は下記のようになります。
# 各ウィジェットの配置
canvas1.pack(
side=tkinter.RIGHT,
)
button1.pack(
side=tkinter.RIGHT,
)
button2.pack(
side=tkinter.RIGHT,
expand=True
)
canvas2.pack(
side=tkinter.RIGHT,
)
アプリ起動時の画面は下のようになります。
expand=True
は複数のウィジェットに指定することも可能です。
# 各ウィジェットの配置
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のみです)。
anchor
anchor
を指定することで、詰め込んだウィジェットをどの方向に寄せるのかを設定することができます。
下記のようなパラメータを指定することができます。
tkinter.N
:上方向tkinter.S
:下方向tkinter.W
:左方向tkinter.E
:上方向tkinter.NW
:左上方向tkinter.NE
:右上方向tkinter.SW
:左下方向tkinter.SE
:右下方向tkinter.CENTER
:中央
上方向と北方向に見立てた方角で考えると覚えやすいです。例えば ↓ こんな感じ
- 上:北(
N
orth) - 右上:北東(
N
orthE
ast) - 左下:南西(
S
outhW
est)
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
)
アプリを起動時の画面は下のようになります。
イメージとしては次のようにウィジェットが配置されています。
まず side
設定& expand
設定に基づいて各ウィジェットが右から順に詰め込まれていきます。
さらにこれらのウィジェットが anchor
に従って指定された方向に寄せられ、アプリ起動時の画面通りに配置されるというイメージです。
fill
fill
を指定することで、ウィジェットを引き伸ばし、与えられたスペースに対していっぱいに広げることができます。
fill
に指定できるパラメータは下記の4つになります。
tkinter.NONE
:引き伸ばししないtkinter.X
:横方向に対してのみ引き伸ばすtkinter.Y
:縦方向に対してのみ引き伸ばすtkinter.BOTH
:縦横両方向に対して引き伸ばす
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=tkinter.X
を指定した青いキャンバスは横方向にのみ引き伸ばされ、fill=tkinter.BOTH
を指定したボタン2は縦横両方向に対して引き伸ばしてウィジェットが大きくなっていることが確認できます。
padx・pady
padx
と pady
を指定することで、ウィジェットの外側の空白サイズを設定することができます。
pady
の設定例は下記のようになります。
# 各ウィジェットの配置
canvas1.pack(
pady=100
)
button1.pack()
button2.pack()
canvas2.pack()
スクリプトを実行すると下のような画面のアプリが起動します。pady=100
を指定した青いキャンバスの周り(上下)に 100 px の空白が付加されています。
ipadx・ipady
padx
と pady
がウィジェットの外側を設定するのに対し、ipadx
と ipady
ではウィジェットの内側の空白サイズを設定することができます。つまり、ウィジェットのサイズが大きくなります。
ipadx
と ipady
の設定例は下記のようになります。
# 各ウィジェットの配置
canvas1.pack()
button1.pack(
ipadx=100,
ipady=100
)
button2.pack()
canvas2.pack()
スクリプトを実行すると下のような画面のアプリが起動します。ipadx=100
と ipady=100
を指定したボタン1の内側(上下左右)に 100 px の空白が付加されています。
before
・after
通常 pack
メソッドでは実行した順番で親ウィジェットに対して詰め込まれていきますが、 before
・after
を指定することで、 この詰め込まれる順番を制御することができます(正確には詰め込まれる順番を制御したようにウィジェットが配置されます)。
before
・after
には他のウィジェットのインスタンスを指定し、これにより pack
メソッドを実行したウィジェットが詰め込まれる順番が下記のように変わります。
before
:指定したウィジェットの前にpack
メソッドを実行したウィジェットが詰め込まれるafter
:指定したウィジェットの後にpack
メソッドを実行したウィジェットが詰め込まれる
before
と after
の設定例は下記のようになります。
# 各ウィジェットの配置
canvas1.pack()
button1.pack()
button2.pack(
after=canvas1
)
canvas2.pack(
before=canvas1
)
スクリプトを実行すると下のような画面のアプリが起動します。
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
メソッド実行時に設定した情報(辞書)を取得することができます。
# button1はボタンのインスタンス
info = button1.pack_info()
pack_forget
pack_forget
は実行したウィジェットを画面から消すメソッドです。
画面からは消えますが、そのウィジェットのインスタンスが消えるわけではないので再度 pack
メソッド等で画面に表示することができます(ただし前回指定した設定は忘れ去られているので再度設定が必要)。
# button1はボタンのインスタンス
button1.pack_forget()
pack
を使用するメリット・デメリット
引数なしでも実行できるのでとにかく簡単に使用できます。私も一番使用するのがこの pack
です。
とりあえずアプリの動作確認を行いたいだけであれば pack()
さえ実行しておけば良いです。
ただし、pack
はウィジェットを1次元に配置することを前提としたメソッドなので、ウィジェットの2次元的な配置には pack
は向きません。
スポンサーリンク
grid
grid
は親ウィジェットを2次元的に複数のセルに分割し、各セルにウィジェットを配置するメソッドです。簡単にウィジェットを2次元的に配列できるところが特徴です。
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
を実行することで親ウィジェットを二次元的にセルに分割し、そのセル内にウィジェットを配置することができます。
上記のスクリプトの場合は、メインウィンドウを下のように 2 x 2 の4つのセルに分割し、さらにそれぞれのセルにウィジェットを配置しています。
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
)
column
・row
column
・row
を指定することで、grid
を実行したウィジェットを親ウィジェットのどのセルにウィジェットを配置するかを設定することができます。column
・row
は “0
” 以上の整数を指定します。
また、grid
メソッド実行時に指定した column
・row
の最大値に応じてセルが自動的に分割されます。
具体的には、column
で指定した値の中の最大値 +1
の列数に、row
で指定した値の中の最大値 +1
の行数に分割されます。
この時、各セルの幅はそのセルの列の中に配置されるウィジェットの中で一番幅が大きいサイズに、各セルの高さはそのセルの行の中に配置されるウィジェットの中で一番高さがが大きいサイズに自動的に調整されます。
ですので、ウィジェットが配置されていないセルのサイズは 0 x 0 になり、見た目的には無い物として扱われます。
各セル全てに配置する必要がなく、下記スクリプトのように column
・row
を飛び飛びに指定しても OK です。
# ウィジェットの配置
canvas1.grid(
column=0,
row=0
)
button1.grid(
column=2,
row=0,
)
button2.grid(
column=1,
row=1
)
canvas2.grid(
column=3,
row=1
)
このスクリプトを実行して起動するアプリの画面は下のようになります。
sticky
sticky
を指定することで、セル内のどの方向にウィジェットを寄せて配置するかを設定することができます。
pack
で紹介した anchor
同様に下記のようなパラメータを指定することができます。
tkinter.N
:上方向tkinter.S
:下方向tkinter.W
:左方向tkinter.E
:上方向tkinter.NW
:左上方向tkinter.NE
:右上方向tkinter.SW
:左下方向tkinter.SE
:右下方向tkinter.CENTER
:中央
さらに sticky
には下記のパラメータについても指定可能です。
tkinter.NSEW
:上下左右
また、sticky
には +
演算子を用いて複数の方向を指定することが可能であり、複数指定した場合は各方向に対してウィジェットを引き伸ばすことができます。
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
に複数の方向を指定する場合の設定例は下記のようになります。
# ウィジェットの配置
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
の効果を説明しておきます。まずウィジェットは右上方向(tkinter.NE
)に配置されます。
さらにそのウィジェットが左上方向(tkinter.NW
)に引き伸ばされます。
最後にその引き伸ばされたウィジェットが下方向(tkinter.S
)に引き伸ばされ、これによりセル内全体にウィジェットが拡大されたことになります。
sticky
に tkinter.NSEW
を指定した場合はセル内の全方向にウィジェットが広がることになります。
columnspan
・rowspan
columnspan
・rowspan
を指定することで、複数のセルにまたがってウィジェットを配置することができます。それぞれ正の整数を指定します(0
はダメです)。
columnspan
を指定した場合、ウィジェットは column
で指定した列から columnspan
列分にまたがって配置されます。
また rowspan
を指定した場合、ウィジェットは row
で指定した行から 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
を指定しない場合はボタン1はボタン2の真上(つまり column=0
、row=0
)に配置されることになります。
しかし、上のスクリプトではボタン1に columnspan=2
を指定しているので column=0
と column=1
の2列分にまたがって配置され、上の図のようなウィジェットの配置になっています。
こんな感じで columnspan
を指定すれば、セルとセルの切れ目の部分にもウィジェットを配置することができます。
また、先ほど説明した sticky
を指定すれば、ウィジェットを複数の列全体に広げて配置するようなことも可能です。
複数の列にまたがってウィジェットを配置したい場合はrownspan
を指定してください。
padx
・pady
・ipadx
・ipady
padx
・pady
・ipadx
・ipady
を grid メソッドに指定することも可能です。
指定の仕方や効果に関しては pack
で紹介したものと同様ですので、説明は省略します。
in_
in_
についても pack
で紹介したものと同様ですので省略します。
スポンサーリンク
grid
関連のメソッド
grid
関連のメソッドも紹介しておきます。
grid_slaves
コレは便利なので覚えておいた方が良いです!
grid_slaves
は実行したウィジェット上に grid
で配置されているウィジェットのリストを取得するメソッドです。
引数の column
と row
により、どこに配置したウィジェットのリストを取得したいかを指定することができます。
例えば下記のようにして grid_slaves
を実行することで、frame1
上の column=2
, row=1
に配置されたウィジェットのリストを取得することができます。
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
メソッド実行時に設定した情報(辞書形式)を取得することができます。
# button1はボタンのインスタンス
info = button1.grid_info()
grid_forget
grid_forget
は実行したウィジェットを画面から消すメソッドです。
画面からは消えますが、そのウィジェットのインスタンスが消えるわけではないので再度 grid
メソッド等で画面に表示することができます(ただし前回指定した設定は忘れ去られているので再度設定が必要)。
# button1はボタンのインスタンス
button1.grid_forget()
grid_remove
grid_remove
は grid_forget
同様に実行したウィジェットを画面から消すメソッドです。
が、grid_remove
はgrid_forget
とは違って前回 grid
メソッド実行時に指定した設定が保持されているので、再度 grid
メソッドを実行すれば(引数なしで)前回と同じ設定で画面に配置することができます。
# button1はボタンのインスタンス
button1.grid_remove()
grid_size
grid_size
はセルの数を返却するメソッドです。具体的にはセルの行数と列数を返却します。ウィジェットの配置先となる親ウィジェットで実行します。
# appは親ウィジェットのインスタンス
app.grid_size()
grid_anchor
grid_anchor
は分割されたセルをどの方向に寄せるかを指定するメソッドです。
pack
の anchor
指定で示した9つのパラメータを指定することができます。
tkinter.N
:上方向tkinter.S
:下方向tkinter.W
:左方向tkinter.E
:上方向tkinter.NW
:左上方向tkinter.NE
:右上方向tkinter.SW
:左下方向tkinter.SE
:右下方向tkinter.CENTER
:中央
grid_anchor
はウィジェットの配置先となる親ウィジェットで実行します。
# appは親ウィジェットのインスタンス
app.grid_anchor(tkinter.CENTER)
grid_columnconfigure
grid_columnconfigure
は列ごとにセルの設定を行うメソッドです。ウィジェットの配置先となる親ウィジェットで実行します。
第1引数には列番号(grid
メソッド実行時に column
で指定した値)を、第2引数以降は、下記に記載した設定をキーワード引数により指定します。
weight
:- 指定した列のセルをウィンドウの余白量に応じて横方向に広げるかどうかの設定
0
:広げない1
以上:広げる(値に応じて広がる割合が増加)
- 指定した列のセルをウィンドウの余白量に応じて横方向に広げるかどうかの設定
minsize
:- 指定した列のセルの横方向最小サイズ(px)
pad
:- 指定した列のセルに対する横方向の余白追加量(px)
ちょっと分かりにくい weight
設定について、下記スクリプトを基に説明したいと思います。
# -*- 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()
実行して起動するアプリの画面は下の図のようになります。
4つのセルに分割され、各ウィジェットに sticky=tkinter.NSEW
をしているのでセルいっぱいにウィジェットが引き伸ばされるため、上の図のようなアプリ画面になっています。
続いて下記を mainloop
実行前に追加して grid_columnconfigure
により column=0
の列に weight=1
を設定します。
# appはメインウィンドウのインスタンス
app.grid_columnconfigure(0, weight=1)
これを追加することで、アプリの起動画面は下の図のように変わります。もともとメインウィンドウの右側にあった余白量の分、column=0
の列のセルの横方向のサイズが広がっていることが確認できると思います。
column=1
の列のセルの横方向のサイズが変化していないのは weight
を設定していないためです(縦方向のサイズを変化させたい場合は次に説明する grid_rowconfigure
メソッドを使用します)。
今度は下記のように column=1
に対して weight=2
を設定してみましょう。
# appはメインウィンドウのインスタンス
app.grid_columnconfigure(0, weight=1)
app.grid_columnconfigure(1, weight=2)
この時のアプリの画面は下の図のようになります。
今度は column=1
の列のセルも広がっていることが確認できると思います。column=1
の方がセルが大きくなっているのは、weight
で指定した値が column=0
よりも大きいためです。
こんな感じで weight
の比率に応じて、その列のセルに与えられる親ウィジェットの余白が増えることになります。
また親ウィジェットの余白量が変われば weight
の比率に応じて各列のサイズも変わります。下の図は column=0
と column=1
両方に対して weight=1
を設定したアプリのメインウィンドウを変化した時のアニメになります。
こんな感じで 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(self, column=None, row=None, col2=None, row2=None)
1つのセルの座標とサイズを取得したい場合は column
と row
の2つを指定します。これにより指定した column
と row
の位置のセルの左上座標とサイズが返却されます。
column
・row
・col2
・row2
の4つの引数を指定することで、複数のセルを指定することも可能です。
この場合は column
から col2
の行および row
から row2
の列の範囲のセルを合体させた時の座標とサイズを取得することができます。
また、引数を指定しなかった場合は、全ての行と全ての行の範囲のセルを合体させた時の座標とサイズを取得することができます。
ただし grid_bbox
はウィジェットの配置が完了し、それが画面に反映された後でなければうまく情報が取得できない点に注意してください。
基本的にウィジェットの配置等が画面に反映されるのは mainloop
実行中や update
メソッド実行後になります。このあたりは下記のメインウィンドウのページで解説しているので詳しく知りたい方は読んでみてください。
したがって、mainloop
実行前は update
メソッド実行しない限りは grid_bbox
を実行してもうまく情報が取得できません。おそらく取得できるデータは (0, 0, 0, 0)
になると思います。
grid
を使用するメリット・デメリット
簡単にウィジェットを2次元的に配置できる点が良いです。
基本的に GUI アプリではウィジェットを2次元的に配列することになりますので、一番使われている方法ではないかと思います。
ウィジェットの数が多くてもそこまで負荷は増えません。
大雑把にウィジェットを配置する点では最強だと思いますが、細かくウィジェットの位置を指定したい場合は次に説明する 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
を実行することで、引数で指定した(x
, y
) 座標にウィジェットが配置されます。
原点は親ウィジェットの左上端で、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
)
x
・y
x
・y
を指定することで、ウィジェットを配置する座標を設定することができます。
ウィジェットの左上を基準に、親ウィジェットの(x
, y
)座標にウィジェットが配置されます(どこを基準にするかは次に説明する anchor
で指定可能です)。
anchor
anchor
を指定することで、ウィジェット配置時のウィジェットの基準位置を指定することができます。
anchor
に指定できるパラメータは Pack
の anchor で示した9種類と同じになります(デフォルトは tkinter.NW
)。
例えば anchor=tkinter.CENTER
を指定すれば、親ウィジェットの(x
, y
)座標にウィジェットの中心が来るようにウィジェットの配置が行われます。
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
)
スクリプトを実行して起動するアプリの画面は下図のようになります。
width
・height
width
・height
を指定することで、ウィジェットの幅と高さを指定することができます。
ピクセル単位で指定します。
place
メソッドに width
・height
を指定することで、ウィジェットのインスタンス作成時に指定した width
・height
は無視されるので注意しましょう。
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
)
スクリプトを実行して起動するアプリの画面は下図のようになります。
各ウィジェットの幅と高さは、ウィジェットインスタンス時に指定した width
・height
ではなく、place
メソッド実行時に指定した width
・height
になってることも確認できると思います。
relx
・rely
relx
・rely
は x
・y
同様にウィジェットを配置する座標を指定する引数になります。
ですが、 x
・y
は親ウィジェット上の座標を単純に指定するのに対し、relx
・rely
は親ウィジェットの幅と高さを “1” とした時の相対位置を指定する点が異なります。
例えば親ウィジェットの中心は relx=0.5
・rely=0.5
になります。
指定できる値は 0.0
〜 1.0
になります。
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
は親ウィジェットの幅と高さを “1” とした時の相対位置となりますので、親ウィジェットのサイズが変わればそれに応じてウィジェットの配置位置も変化する点もポイントです。
relwidth
・relheight
relwidth
・relheight
は width
・height
同様にウィジェットの幅と高さを指定する引数になります。
ですが、 width
・height
はピクセル単位で指定するするのに対し、relwidth
・relheight
は親ウィジェットの幅と高さを “1” とした時の相対的なサイズを指定する点が異なります。
例えば親ウィジェットの幅と高さそれぞれの半分のサイズを表す場合は relwidth=0.5
・relheight=0.5
になります。
指定できる値は 0.0
〜 1.0
になります。
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
は親ウィジェットの幅と高さを “1” とした時の相対サイズとなりますので、親ウィジェットのサイズが変わればそれに応じてウィジェットの幅と高さも変化する点もポイントです。
上記スクリプトではウィジェットの位置も相対位置である relx
・rely
を指定しているため、ウィジェットの位置も幅・高さも親ウィジェットのサイズに応じて変化します。
なので親ウィジェットのサイズ変更によるレイアウトの崩れはありません(文字のサイズなどのウィジェットの中身は別途リサイズ対応が必要)。
bordermode
bordermode
を指定することで、ウィジェットを配置する親ウィジェットの基準位置、つまり(0, 0)座標を「外枠の外側」にするか「外枠の内側」にするかを指定することができます。
bordermode
に指定するパラメータは下記の2つになります。
tkinter.INSIDE
:ウィジェットを配置する親ウィジェットの基準位置を「外枠の内側」とするtkinter.OUTSIDE
:ウィジェットを配置する親ウィジェットの基準位置を「外枠の外側」とする
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)に配置されていることが確認できると思います。
bordermode
の指定部分のみを bordermode=tkinter.OUTSIDE
に変更した場合のアプリ画面は下のようになります。
今度は親ウィジェットの外枠の外側を基準位置として指定した位置(0, 0)に配置されていることが確認できると思います。
in_
in_
を指定することで、ウィジェットの配置先となる親ウィジェットを設定することができます。
place
関連のメソッド
place
関連のメソッドも紹介しておきます。
place_info
place_info
は実行したウィジェットに対する place
の情報を取得するメソッドです。
要は place
メソッド実行時に設定した情報(辞書形式)を取得することができます。
# button1はボタンのインスタンス
info = button1.place_info()
place_forget
place_forget
は実行したウィジェットを画面から消すメソッドです。
画面からは消えますが、そのウィジェットのインスタンスが消えるわけではないので再度 place
メソッド等で画面に表示することができます(ただし前回指定した設定は忘れ去られているので再度設定が必要)。
# button1はボタンのインスタンス
button1.place_forget()
スポンサーリンク
place
を使用するメリット・デメリット
考え方は一番シンプルだと思います。私はこの方法が一番好きですね。一番ウィジェットの位置を細かく指定できる方法でもあります。
ただし座標を指定する必要があるので座標を計算するのが大変です。
特にウィジェットの数が多ければ多いほど座標を計算する負荷が増えます。
まとめ
このページでは Tkinter でのウィジェットの配置について説明しました。
配置するために利用するメソッドには下記の3種類があります。それぞれ特徴が異なるのでこの特徴だけはしっかり覚えておきましょう!
pack
:ウィジェットをある方向にどんどん詰め込むgrid
:2次元的に親ウィジェットをセルに分割し、セル内にウィジェットを配置するplace
:配置する座標を指定してウィジェットを配置する
用途としては、とにかくウィジェットを配置したいだけなら pack
、簡単にウィジェットを2次元的に配置したいなら grid
、座標計算が得意な人は place
といった感じかなあと思います。
また、各メソッド実行時には様々な引数が指定可能であり、細やかな設定を行うことができます。各メソッドに対して指定可能な全引数をこのページでまとめていますので、困ったときに参照していただければと思います!