HOME Python 書き込む

2. Widget を配置しよう


1. 初めに

Tkinter は widget を配置する方法として pack, grid, place の3つの方法があり、 3つとも widget のメソッドとして定義されています。また、配置の枠組みを決める Frame という widget があります。Frame 自身はほとんど何も表示しませんが、widget をまとめるのに使います。

まず、Frame について説明して、それから、pack, grid, place の順に説明していきます。

2. Frame

3. pack

pack は widget を縦または横に1次元的に配列するときに使います。pack には以下の option があります。
属性 説明
anchor 配置可能なスペースに余裕がある場合、Widget をどこに配置するか指定します。デフォルトは Tk.CENTER. そのほかに、Tk.W (左よせ)、Tk.E (右よせ)、Tk.N (上よせ)、Tk.S (下よせ)、 Tk.NW (左上)、Tk.SW (左下)、Tk.NE (右上)、Tk.SE (右下)があります。 詳しくは、 Tkinter reference: 4.5. Anchors を見てください。
expand 親 widget が大きくなったとき、大きくなるかどうかを指定します。 1 を指定すると大きくなり、0 だとなりません。デフォルトは 0
fill widget が空いているスペースを埋めるかどうか指定します: Tk.NONE, 元のサイズを保持します。 Tk.X, 横に広がります。 Tk.Y, 縦に広がります。 Tk.BOTH, 縦横に広がります。
padx 外側の横の隙間を指定します。
pady 外側の縦の隙間を指定します。
ipadx 内側の横の隙間を指定します。
ipady 内側の縦の隙間を指定します。
side どの方向からつめていくかを指定します:Tk.TOP (default), 上からつめます。 Tk.LEFT, 左からつめます。Tk.RIGHT, 右からつめます。Tk.BOTTOM, 下からつめます。

3.1. ラベルを3つ縦に並べる。

簡単な例としてラベルを3つ縦に並べることを考えてみましょう。 ラベルの幅を違えるため、文字列を長いのと短いのを表示させます。 また、境界をはっきりさせるため、relief=Tk.RIDGE を指定し、背景色をつけましょう。 まずは普通に縦に配置してみます。
[code 1] にコードを示します。

[code 1]

01:     #! /usr/bin/env python
02:     
03:     """
04:     three_labels_a.py
05:     
06:     pack three labels from the TOP.
07:     No option of pack is used.
08:     """
09:     
10:     
11:     import Tkinter as Tk
12:     
13:     class Frame(Tk.Frame):
14:         """ Frame with three label """
15:     
16:         def __init__(self, master=None):
17:             Tk.Frame.__init__(self, master)
18:             self.master.title('Pack Three Labels')
19:     
20:             # First Label
21:             la = Tk.Label(self, text='Hello everybody. How are you?',  bg='yellow', relief=Tk.RIDGE, bd=2)
22:             la.pack()
23:     
24:             # Second Label
25:             lb = Tk.Label(self, text='Oh My God!', bg='red', relief=Tk.RIDGE, bd=2)
26:             lb.pack()
27:     
28:             # Third Label
29:             lc = Tk.Label(self, text='See you tomorrow.', bg='LightSkyBlue', relief=Tk.RIDGE, bd=2)
30:             lc.pack()
31:     
32:     ##----------------
33:     if __name__ == '__main__':
34:         f = Frame()
35:         f.pack()
36:         f.mainloop()
このコードでは、Tk.Frame クラスの導出クラスとして Frame クラスを定義し、その中にラベルを配置していきます。 Python の GUI プログラムは Tkinter に限らず、このような形で書くのが一般的です。

このコードを実行すると [図 1] のような widget が生成します。

[図 1]

22, 26, 30 行目の pack に padx=5, pady=5 のオプションをつけると [図 2] のようにラベルの間に隙間ができます。

[図 2]

pack のオプションを padx=5, pady=5, fill=TK.X とすると [図 3] のようにラベルが横に広がります。

[図 3]

pack のオプションを padx=5, pady=5, anchor=Tk.W とすると [図 4] のようにラベルが左寄せになります。。

[図 4]

4. grid

2次元的に配置するときは grid を使います。grid には以下の option があります。
属性 説明
column 配置する列です。
columnspan 何列にわたって配置するかを指定します。デフォルトは 1 です。
padx 外側の横の隙間を指定します。
pady 外側の縦の隙間を指定します。
ipadx 内側の横の隙間を指定します。
ipady 内側の縦の隙間を指定します。
row 配置する行です。
rowspan 何行にわたって配置するかを指定します。デフォルトは 1 です。
sticky pack の anchor と fill をあわせた属性です。 スペースに余裕がある場合、どこに配置するか、どのように引き伸ばすかを指定します。
指定できる値は anchor と同じ、Tk.CENTER, Tk.W, Tk.E, Tk.N, Tk.S, Tk.NW, Tk.NW, Tk.SW, Tk.SE です。 位置決めには値を単独で、引き伸ばす場合には値を '+' して指定します。
たとえば、左寄せは sticky=Tk.W, 上よせは sticky=Tk.N
左右に引き伸ばすには sticky=Tk.W + Tk.E, 上下に引き伸ばすには sticky=Tk.N + Tk.S,
全体に引き伸ばすには sticky=Tk.W + Tk.E + Tk.N + Tk.S

4.1. ラベルを3つ、上段に1つ、下段に2つ配置する。

3.1. と同じ3つのラベルを上段に1つ、下段に2つ配置してみましょう。
コードを [code 2] 示します。pack を使った場合とほとんど同じです。

[code 2]

01:     #! /usr/bin/env python
02:     
03:     """
04:     three_labels_b.py
05:     
06:     grid three labels from the TOP.
07:     one at row=0, other two at row=1
08:     """
09:     
10:     
11:     import Tkinter as Tk
12:     
13:     class Frame(Tk.Frame):
14:         """ Frame with three label """
15:     
16:         def __init__(self, master=None):
17:             Tk.Frame.__init__(self, master)
18:             self.master.title('Pack Three Labels')
19:     
20:             # First Label
21:             la = Tk.Label(self, text='Hello everybody.',  bg='yellow', relief=Tk.RIDGE, bd=2)
22:             la.grid(row=0, column=0, columnspan=2, padx=5, pady=5)
23:     
24:             # Second Label
25:             lb = Tk.Label(self, text='Oh My God!', bg='red', relief=Tk.RIDGE, bd=2)
26:             lb.grid(row=1, column=0, padx=5, pady=5)
27:     
28:             # Third Label
29:             lc = Tk.Label(self, text='See you tomorrow.', bg='LightSkyBlue', relief=Tk.RIDGE, bd=2)
30:             lc.grid(row=1, column=1, padx=5, pady=5)
31:     
32:     ##----------------
33:     if __name__ == '__main__':
34:         f = Frame()
35:         f.pack()
36:         f.mainloop()
このコードを実行して生成する widget は [図 5] のようになります。

[図 5]

22 行目の grid のオプションを row=0, column=0, columnspan=2, padx=5, pady=5, sticky=Tk.W+Tk.E に変更して、上のラベルを横に広げて見ましょう。結果は [図 6]のようになります。

[図 6]

今度は 22 行目の grid のオプションを row=0, column=0, columnspan=2, padx=5, pady=5, sticky=Tk.W に変更して、上のラベルを左寄せして見ましょう。結果は [図 7] のようになります。

[図 7]

5. place

配置を直接指定する方法です。pack や grid でうまく配置できないときにつかいます。 place の option は以下の通りです。
属性 説明
anchor pack と同じ、デフォルトは Tk.NW
bordermode 縁を内側 (Tk.INSIDE) か外側(Tk.OUTSIDE)につける。デフォルトは Tk.INSIDE
height 高さを pixel で指定。
relheight 親 widget に対する相対的な高さを 0.0 -- 1.0 の実数で指定。
relwidth 親 widget に対する相対的な幅を 0.0 -- 1.0 の実数で指定。
relx 親 widget に対する相対的な横の位置を 0.0 -- 1.0 の実数で指定。デフォルトは 0
rely 親 widget に対する相対的な横の位置を 0.0 -- 1.0 の実数で指定。デフォルトは 0
width 幅を pixel で指定。
x 横の位置を pixel で指定。デフォルトは 0
y 縦の位置を pixel で指定。デフォルトは 0

[code 3] に place を使った例を挙げます。 widget を斜めにずらして配置するときには place を使うとすっきりと記述できます。 place メソッドを使うときは親フレームの width と height をあらかじめ指定しておく必要があります。

[code 3]

01:     #! /usr/bin/env python
02:     
03:     """
04:     three_labels_p.py
05:     
06:     place three labels using place method.
07:     """
08:     
09:     
10:     import Tkinter as Tk
11:     
12:     class Frame(Tk.Frame):
13:         """ Frame with three label """
14:     
15:         def __init__(self, master=None):
16:             Tk.Frame.__init__(self, master, height=100, width=200)
17:             self.master.title('Pack Three Labels')
18:     
19:             # First Label
20:             la = Tk.Label(self, text='Hello everybody. How are you?',  bg='yellow', relief=Tk.RIDGE, bd=2)
21:             la.place(relx=0.02, rely=0.1, relheight=0.3, relwidth=0.95)
22:     
23:             # Second Label
24:             lb = Tk.Label(self, text='Oh My God!', bg='red', relief=Tk.RIDGE, bd=2)
25:             lb.place(relx=0.15, rely=0.45)
26:     
27:             # Third Label
28:             lc = Tk.Label(self, text='See you tomorrow.', bg='LightSkyBlue', relief=Tk.RIDGE, bd=2)
29:             lc.place(relx=0.5, rely=0.75)
30:     
31:     ##----------------
32:     if __name__ == '__main__':
33:         f = Frame()
34:         f.pack()
35:         f.mainloop()
[図 8] に生成する widget を示します。

[図 8]

6. Frame を入れ子にする

Frame を入れ子にすることによって、複雑な window を作ることができます。 [code 4] に例を示します。この Frame は f1 と f2 を内部に含み、f1 と f2 は それぞれ4つのラベルを含みます。

[code 4]

01:     #! /usr/bin/env python
02:     
03:     """
04:     nested_frames.py
05:     
06:     """
07:     
08:     
09:     import Tkinter as Tk
10:     
11:     class Frame(Tk.Frame):
12:         """ Frame with two frames inside """
13:     
14:         def __init__(self, master=None):
15:             Tk.Frame.__init__(self, master, height=200, width=200)
16:             self.master.title('Nested Frames')
17:     
18:             # First Frame
19:             f1 = Tk.Frame(self, relief=Tk.RIDGE, bd=2)
20:             for text, color in [('A', 'magenta'), ('B', 'yellow'), ('C', 'SeaGreen'), ('D', 'LightSkyBlue')]:
21:                 l=Tk.Label(f1, text=text, bg=color, font=('Helvetica', '16'))
22:                 l.pack(side=Tk.LEFT)
23:             f1.place(relx=0.2, rely=0.2)
24:             
25:             # Second Frame
26:             f2 = Tk.Frame(self, relief=Tk.RIDGE, bd=2)
27:             for i, (text, color) \
                        in enumerate([('A', 'magenta'), ('B', 'yellow'), ('C', 'SeaGreen'), ('D', 'LightSkyBlue')]):
28:                 l=Tk.Label(f2, text=text, bg=color, font=('Helvetica', '16'))
29:                 l.grid(row=i/2, column=i%2)
30:             f2.place(relx=0.6, rely=0.6)
31:     
32:     
33:     ##----------------
34:     if __name__ == '__main__':
35:         f = Frame()
36:         f.pack()
37:         f.mainloop()
[code 4] を動かすと [図 9] の window が生成します。

[図 9]

7. 終わりに

今回の話は少し退屈だったかもしれません。しかし、widget の配置の方法を知らないと先に進めないので、 少し丁寧に説明しました。

次回からはそれぞれの widget について解説していきます。