いまさらだけど Python を学習する:GUIプログラミング2

かなり間があきましたが、今回は「いまさらpython学習」の5回目です。前回はざっくりボタンやテキストボックスなどのウィジェットを適当に配置し、GUIプログラミングを体験してみました。今回は、少しまともにレイアウトを考えてみたいと思います。

レイアウトをおこなうためには、packgridplace というメソッドが利用できるようです。簡単に説明しておくと、pack は 縦もしくは横に単純にウィジェット並べていく(順に詰め込んでいく)ようなイメージのレイアウトになります。grid は 表形式でウィジェットを配置していくイメージです。HTMLのtableタグや、エクセルなどを思い浮かべてもらってそのマスにウィジェットを配置していくイメージです。placeは、指定個所にウィジェットを配置していきます。

前回の記事はこちら

さて、今回は「いまさらpython学習」の4回目です。前回までにデバッグの準備をしてきました。文法はいいサイトもたくさんあるので、今更このサイトで細かく紹介しても仕方ないなと思...

メリット・デメリット

それぞれのメソッドのメリット、デメリットは以下のような感じ。今回(このブログ)は、gridを採用(多用)していきたいと思いますので、gridについて、記載していきます。

pack

メリット:他の2つに比べてない?(一番簡単といわれているが・・・。)
デメリット:1次元(1列または1行)でしか配置できない。

grid

メリット:全ウィジェットの座標を把握しなくても、ざっくりできれいに配置できる。
デメリット:細かい配置は難しい(隣接するのセルの大きさに影響されズレが生じる)
https://tkdocs.com/tutorial/grid.html

place

メリット:指定個所に配置できるので、レイアウトを細かく指定できる
デメリット:全ウィジェットの座標を把握しておく必要があり、再配置の時などはかなり手間となる

スポンサーリンク

grid

さて前述の通り、本ブログでは、grid を紹介していこうと思います。gridは、行・列(表)でウィジェット配置していきます。

4回目で適当にウィジェットを配置した、以下のウィンドウを修正していこうと思います。

とりあえず、配置する行列を指定

grid で行列配置するには、 rowcolumn を利用して、配置する行列の位置を指定します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import tkinter

main = tkinter.Tk()
main.title("Hello Tkinter")
main.geometry("300x300")

text = tkinter.Label(main, text="Hello python.")
text.grid(row=0, column=0)

btn = tkinter.Button(main, text="Click ME!")
btn.grid(row=1, column=1)

txtbox = tkinter.Entry(main,width=30)
txtbox.grid(row=1, column=0)

rbtn1 = tkinter.Radiobutton(main, text='select 1')
rbtn1.grid(row=2, column=0)

rbtn2 = tkinter.Radiobutton(main, text='select 2')
rbtn2.grid(row=2,column=1)

rbtn3 = tkinter.Radiobutton(main, text='select 3')
rbtn3.grid(row=2,column=2)

chbox = tkinter.Checkbutton(main, text='Check ME!')
chbox.grid(row=3,column=0)

main.mainloop()

rowcolumn で配置する行列の位置を指定していますが、やったことがある方は、すぐにこのコードは変だと気付くと思います。以下のような「くずれた」レイアウトになります。

この例は各行で列の数が等しく指定されていない(1行目が1列、2行目が2列、3行目が3列、4行目が1列とバラバラ)ためです。

行毎の列数(列毎の行数)が等しくなるように配置

先ほどの例に対して、行や列をまたがせて、綺麗に4行3列になるようにしてみます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import tkinter

main = tkinter.Tk()
main.title("Hello Tkinter")
main.geometry("300x300")

text = tkinter.Label(main, text="Hello python.")
text.grid(row=0, column=0,columnspan=3)

btn = tkinter.Button(main, text="Click ME!")
btn.grid(row=1, column=2)

txtbox = tkinter.Entry(main,width=30)
txtbox.grid(row=1, column=0,columnspan=2)

rbtn1 = tkinter.Radiobutton(main, text='select 1')
rbtn1.grid(row=2, column=0)

rbtn2 = tkinter.Radiobutton(main, text='select 2')
rbtn2.grid(row=2,column=1)

rbtn3 = tkinter.Radiobutton(main, text='select 3')
rbtn3.grid(row=2,column=2)

chbox = tkinter.Checkbutton(main, text='Check ME!')
chbox.grid(row=3,column=0,columnspan=3)

main.mainloop()

列をまたぎたい場合は、columnspan を利用します。(行をまたぎたい場合は、rowspan を利用します。)「またぐ」とは、エクセルでいうセルの結合をイメージしてもらうとわかりやすいと思います。それぞれ、またぎたい数を指定します。これで、それなりに整ってきました。

左に寄せ右寄せを使う

3列に跨がせたので、一番上のテキスト「Hello python.」が中央よりになってしまっています。これを左寄せにして、ついでにチェックボックスの「Click ME!」右寄せにしてみます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import tkinter

main = tkinter.Tk()
main.title("Hello Tkinter")
main.geometry("300x300")

text = tkinter.Label(main, text="Hello python.")
text.grid(row=0, column=0,columnspan=3,sticky=tkinter.W)

btn = tkinter.Button(main, text="Click ME!")
btn.grid(row=1, column=2)

txtbox = tkinter.Entry(main,width=30)
txtbox.grid(row=1, column=0,columnspan=2)

rbtn1 = tkinter.Radiobutton(main, text='select 1')
rbtn1.grid(row=2, column=0)

rbtn2 = tkinter.Radiobutton(main, text='select 2')
rbtn2.grid(row=2,column=1)

rbtn3 = tkinter.Radiobutton(main, text='select 3')
rbtn3.grid(row=2,column=2)

chbox = tkinter.Checkbutton(main, text='Check ME!')
chbox.grid(row=3,column=0,columnspan=3,sticky=tkinter.E)

main.mainloop()

右寄せ左寄せには、sticky を使います。それぞれ、左右によりましたね。

sticky には以下のようなものが指定できます。
tkinter.CENTER(中)、tkinter.W(左)、tkinter.E(右)、tkinter.N(上)、tkinter.S(下)、tkinter.NW(左上)、tkinter.NE(右上)、tkinter.SW(左下)、tkinter.SE(右下) です。
また、引き伸ばしの指定ができて、
tkinter.W + tkinter.E で左右に引き伸ばし、tkinter.N + tkinter.S で上下に引き伸ばせます。
tkinter.W + tkinter.E + tkinter.N + tkinter.S で全体に引き伸ばせます。

隙間をあける

気になった方も多いと思いますが、左側がウィンドウ枠ぎりぎりにくっついていて少し見苦しいです。隙間をあけてみます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import tkinter

main = tkinter.Tk()
main.title("Hello Tkinter")
main.geometry("300x300")

text = tkinter.Label(main, text="Hello python.")
text.grid(row=0, column=0,columnspan=3,padx=10,pady=5,sticky=tkinter.W)

btn = tkinter.Button(main, text="Click ME!")
btn.grid(row=1, column=2,padx=10)

txtbox = tkinter.Entry(main,width=30)
txtbox.grid(row=1, column=0,columnspan=2,padx=10)

rbtn1 = tkinter.Radiobutton(main, text='select 1')
rbtn1.grid(row=2, column=0,pady=5)

rbtn2 = tkinter.Radiobutton(main, text='select 2')
rbtn2.grid(row=2,column=1)

rbtn3 = tkinter.Radiobutton(main, text='select 3')
rbtn3.grid(row=2,column=2)

chbox = tkinter.Checkbutton(main, text='Check ME!')
chbox.grid(row=3,column=0,columnspan=3,sticky=tkinter.E)

main.mainloop()

隙間をあけるには、padxpady を使います。

これで、それっぽく配置できました。

おわりに

先ほどのウィンドウでも、若干 select2 の位置がズレているように見えたと思います。これは、2行目のEntry(テキストボックス)の長さが長く、1,2列めと3列目の幅が等間隔にならず、ズレが生じています。少しEntry(テキストボックス)の長さを短くするか、さらにこだわって綺麗に配置したい場合は、place を使うのがよさそうです。width=25 とするとこんな感じになりました。

長さや高さの異なるものを配置する場合、それに依存して(セルが広がり)、隣接するウィジェットの配置位置がずれてしまう。というデメリットを見てもらえたかと思います。