「Pack ジオメトリマネージャ」の版間の差分

提供: tknotebook
移動: 案内検索
(Frameウィジェットを必要最小限の面積にしてみる(pack()の既定の動作))
(Frameウィジェットを必要最小限の面積にしてみる(pack()の既定の動作))
172行: 172行:
  
  
上のコードでは Frameの自動縮小を抑えるためのおまじない frame.pack_propagate(False)frame.pack_propagate(False) を削除しています。
+
上のコードでは Frameの自動縮小を抑えるためのおまじない frame.pack_propagate(False) を削除しています。
 
またわかりやすいように Frameウィジェットの背景色を green(緑) にしました。結果は以下のようになります。
 
またわかりやすいように Frameウィジェットの背景色を green(緑) にしました。結果は以下のようになります。
  

2018年8月24日 (金) 12:20時点における版

メインページ>コンピュータの部屋#Python>Tkinter Tips

Tkinterにはウィジェットをウィンドウ上に配置するための「ジオメトリマーネジャ」があります。 ジオメトリマネージャとは、ウィジェットの位置や大きさを決定する仕掛けです。

TkInterには Pack, Grid, Place の3種類のジオメトリマネージャがありますが、この記事では Pack ジオメトリマネーを紹介します。

Pack ジオメトリマネージャとは?

Pack ジオメトリマネージャとは、ウィジェットを「積めて」配置してゆくタイプのジオメトリマネージャです。所謂エラスティックなGUIデザインを実現してくれます。 言葉で説明するのは難しいので図を使って説明しましょう。

packメソッドを使ってみる

まず最初は最も簡単なコードを紹介しましょう。ウィンドウ全面に貼られた FrameウィジェットにButtonを貼り付けてみます。

import tkinter as tk

root = tk.Tk()

frame = tk.Frame(root, width=200, height=200)
frame.pack_propagate(False)
frame.pack()
tk.Button(frame, text="A").pack()


root.mainloop()

これを実行すると、こんな感じになります。

Pack frame 01.png

このコードでは pack() メソッドの動きが分かりやすくなるように、ちょっとしたおまじないのコードを使っています。

frame.pack_propagate(False)

tk.Button(frame, text="A").pack()

の影響が Frameウィジェットに及ぶのを防ぐためのコードです。このコードがないと、 Frameのサイズは Buttonウィジェットを表示するのに必要な最小限のサイズに自動的にリサイズします。

frame.pack_propagate(False)

としておくと、Frameウィジェットの大きさは コンストラクタに渡した width, height パラメータの値のままに保たれます。

ここで何が起きているかを簡単に説明しておきましょう。

tk.Button(frame, text="A").pack()

を実行すると、Buttonウィジェットは frameウィジェットの上端に張り付きます。

Pack 図面01.png

図の黄色いところは「Packメソッドによって ButtonウィジェットがFrameウィジェット上に確保したエリア」です。 これは、Buttonウィジェットのサイズとは異なることに注意してください。 「Packメソッドによって ButtonウィジェットがFrameウィジェット上に確保したエリア」はFrameオブジェクトの最上端に、Buttonウィジェットのテキストを表示するのに必要なだけの高さが確保され、横方向はFrameの横方向全体が確保されます。Buttonは確保されたエリアの「中央」に表示されるのです。

packメソッドを2つ使ってみる

これまで

tk.Button(frame, text="A").pack()

というコードでButtonウィジェットを配置してきましたが、実はこれは

tk.Button(frame, text="A").pack(side=tk.TOP)

と同じです。side=tk.TOP は親ウィジェットの上端にウィジェットを配置することを意味します。 ではこれを2回連続して使ったらどうなるでしょうか?

import tkinter as tk

root = tk.Tk()

frame = tk.Frame(root, width=200, height=200)
frame.pack_propagate(False)
frame.pack()
tk.Button(frame, text="A").pack(side=tk.TOP)
tk.Button(frame, text="B").pack(side=tk.TOP)

root.mainloop()

を実行すると、下図のように縦積みになって表示されます。

Pack frame 02.png

これはつまり、Buttonウィジェットが下図のように自身を表示するエリアを確保するからです。

Pack 図面02.png

つまり2番目のButtonウェイジェットは1番目のボタンウィジェットで確保されたエリアを除いた部分のFrameウィジェットのエリアの最上端を確保するのです。

side=tk.LEFT を使ってみる

さてここまでは side=tk.TOP だけ使ってきましたが size=tk.Left と組み合わせてみましょう。

import tkinter as tk

root = tk.Tk()

frame = tk.Frame(root, width=200, height=200)
frame.pack_propagate(False)
frame.pack()
tk.Button(frame, text="A").pack(side=tk.TOP)
tk.Button(frame, text="B").pack(side=tk.LEFT)

root.mainloop()


を実行すると、下図のように、今度は BボタンがFrameウィジェットの左側に貼り付いて表示されます。

Pack frame 03.png

BボタンはFrameウィジェットの左側に張り付いてますが、少し縦中央より下に表示されていることにお気づきでしょうか? このずれは以下の図を見ればわかります。

Pack 図面03.png

図からわかるように、BボタンはFrameウィジェットのAボタンが占めていない残りの部分の左側に張り付きます。 side=tk.LEFT で左へ張り付く場合、ボタンの占めるエリアは、幅はボタンのキャプションを表示するのに十分なだけの幅になりますが、 縦はFrameウィジェットのAボタンが占めていない残りの部分の高さと同じになります。つまり高さはとれるだけ目いっぱいになるのです。

Bボタンはこうして取られたエリアの中央に置かれまず。だからFrameウィジェットの中央より若干下になるのです。

tk.Bottom, tk.Right も使ってみる

そろそろなれたでしょうから、tkBottomと tk.Right も使ってみましょう。 もうすでに察しはついていると思いますが、tk.Bottom はウィジェットをに、tk.Right はウィジェットを右に張り付かせる指定です。

import tkinter as tk

root = tk.Tk()

frame = tk.Frame(root, width=200, height=200)
frame.pack_propagate(False)
frame.pack()
tk.Button(frame, text="A").pack(side=tk.TOP)
tk.Button(frame, text="B").pack(side=tk.LEFT)
tk.Button(frame, text="C").pack(side=tk.BOTTOM)
tk.Button(frame, text="D").pack(side=tk.RIGHT)

root.mainloop()

このコードを実行すると、既に予想されていると思いますが、下の図のようになります。

Pack frame 04.png

もうわかっているとは思いますが、念のため、ボタンの確保したエリアとボタンの位置を図で示しておきましょう。

Pack 図面04-1.png

Frameウィジェットを必要最小限の面積にしてみる(pack()の既定の動作)

ここまで、Frameウィジェットのサイズは強制的に 200 x 200 にしてきましたが、pack()メソッドの本来の動作では Frameウィジェットは、ボタンを表示する最小限の大きさに自動縮小します。上で示した4個のボタンの場合で試してみましょう。

import tkinter as tk

root = tk.Tk()

frame = tk.Frame(root, width=200, height=200, bg="green", )
#frame.pack_propagate(False)
frame.pack()
tk.Button(frame, text="A").pack(side=tk.TOP)
tk.Button(frame, text="B").pack(side=tk.LEFT)
tk.Button(frame, text="C").pack(side=tk.BOTTOM)
tk.Button(frame, text="D").pack(side=tk.RIGHT)

root.mainloop()


上のコードでは Frameの自動縮小を抑えるためのおまじない frame.pack_propagate(False) を削除しています。 またわかりやすいように Frameウィジェットの背景色を green(緑) にしました。結果は以下のようになります。

Pack frame 05.png

この動作を一口で説明するのは大変難しいです。

Frameの大きさが固定の場合は、ボタンは tk.XXX の指定に従って Frame の四隅に張り付くだけでした。 Frameの大きさは十分広く、ボタンを表示するだけの十分なエリアがありました。

実はボタンにはボタンを表示するための必要最小限のサイズがあります。ボタンの場合、既定ではボタンのテキスト(キャプション)を表示するのに必要な大きさのことです。

Packジオメトリマネージャは Frame の大きさを色々変えてみてボタンを貼り付け、全てのボタンのテキストが全て正常に表示できるような最小の大きさに Frameウィジェットのサイズを決めてくれるのです。