Tkinter は、Anaconda で標準インストールされる PythonのGUI用パッケージです。
本格的はGUIアプリの開発なら、 Microsoft のVisual Studio + C#又は VB.NETを使った開発手法が有効ですが、ちょっとしたGUI程度なら Tkinter を使うことでも実現できます。
ただ、Tkinterはかなり高機能なパッケージであり、それなりの前提知識(基本的な考え方、Windowやコントロールの階層、配置方法など)が無いと、意図した画面を作れません。
そして、前提知識を習得するために時間をかけて様々なサイトを調べることとなり、大変非効率です。
今回は、Tkinterをこれから始めて使う方を対象に、知っておきたい前提知識を一通り纏めています。
実際にプログラムをどう書けばよいかの具体例、コントロールの使い方については、実用編にまとめていますので、そちらをご覧ください。
Tkinterで作った具体例
下記の動画は、Tkinterを使って出来るGUIの具体例です。
これ以外にも、スクロールバーやタブを用いた、かなり複雑な画面を作ることも可能ですが、今回は必要最小限に限定するため省略しています。
本記事でTkinterの大枠を理解した後で、Tkinter公式サイトを見ていただき、さらに必要なコントロールを探もらえればと思います。
GUIの作成手順
Tkinter でGUIを作るには、最初にTKinterのインスタンスを生成し、WindowタイトルとWindoサイズを指定、あとはテキストボックスやボタンなどのコントロールを必要な分だけ生成&張り付けを行い、最後に mainloop メソッドを呼び出すだけです。
GUIの考え方
Tkinterは、ルートのWindow、複数のコントロールを束ねて管理する Frame 、最小単位となるコントロールという3種類のオブジェクトを使ってGUIを作成します。
オブジェクトの階層構造
ルートのWindowには複数のFrameを持たせることが可能で、またFrameの中に入れ子として別のFrameを置くことも可能です。
コントロールはラベルやボタンなどUIをつかさどるオブジェクトで、ルートのWindowとFrameのどちらにも置くことが出来ます。
親子関係の指定方法
最初に Tk クラスのインスタンスを生成する際、戻り値としてルート(最初の親)となるWindowオブジェクトを受取ることができます。
これを引数として Frame クラスのインスタンスを生成すると、root の子供として Frameオブジェクト が生成されます。
ラベルやコンボボックスなどの各コントロールクラスに対して、第一引数にFrameオブジェクトを渡すことで、そのFrameの子供としてコントロールオブジェクトが生成されます。
コントロールオブジェクトの引数には ルートWindowのオブジェクトを渡すことも可能で、その場合はルートWindowに対する直接の子供となるコントロールが生成できます。
第一引数を省略すると全てがルートWindowの子供となる
各コントロールの第一引数に何も渡さず、コントロールのオブジェクトを生成することも可能です。
この場合は、自動的にルートWindowオブジェクトが各コントロールの親になります。
特にFrameを使わず、簡単なGUIを作成する場合は、次の様に記述が可能です。
コントロールの配置
ルートWindowにFrameやコントロールを配置したり、Frameにコントロールを配置するためのメソッドとして、pack、grid、place というメソッドが存在します。
pack | コントロールを上から順番に配置する。 |
---|---|
grid | Window又はFrameを格子(グリッド)状に分割し、row と column で指定した場所に配置する |
place | 左上を起点(0,0)としたXY座標で示した場所に配置する |
pack と grid は混在して使うことは出来ませんが、pack と place、grid と place は混在可能です。
しかし、実際に使う場合はどれか1つに統一しておく方が良いと思います。
アンカーと余白指定
アンカーと余白指定は、ルートWindowやFrame上にコントロールを配置する上で共通となります。
アンカーは親に対してFrameやコントロールの端を固定する引数で、tk.NW、kt.W・・・・など9種類の指定が可能です。
padx,pady は親に対しての上下左右の余白、ipadx,ipady はコントロール内の余白を指定する引数です。
尚、packでの配置は上から順に処理されるだけなので、anchor には左端、中央、右端 しか指定できない(厳密には、tk.NW、tk.W、tk.SW のどれを指定しても tk.Wとして動作する)など、一部制約もあります。
packによる配置
pack は、そのメソッドが呼ばれた順番にコントロールを配置していきます。
この時、anchor を指定することで、右端、中央、左端を指定できます。
属性 | 説明 |
---|---|
anchor | 配置可能なスペースに余裕がある場合、コントロールをどこに配置するか指定する。初期値は tk.CENTER。 tk.W (左寄せ)、tk.E (右寄せ)、tk.N (上寄 せ)、tk.S (下寄 せ)、 tk.NW (左上)、tk.SW (左下)、tk.NE (右上)、tk.SE (右下)。 |
expand | 親のサイズに連動して、自分自身のサイズを拡大、縮小させるか否かの指定。 1 =連動、0=連動しない。初期値は 0 |
fill | 空いているスペースをコントロールが埋めるかの指定。 tk.NONE=元のサイズを維持、tk.X, 横に広がる、tk.Y, 縦に広がる、tk.BOTH=縦横に広がる。 |
padx | 外側のX方向の余白を指定。 |
pady | 外側のY方向の余白を指定。 |
ipadx | 内 側のX方向の余白を指定。 |
ipady | 内 側のY方向の余白を指定。 |
side | 配置する方向を指定する。初期値はtk.TOP (上から) tk.LEFT=左から、tk.RIGHT= 右から、tk.BOTTOM=下から配置する。 |
grid による配置
grid は画面を格子状の区画に分けて、行(row) と 列(column)で指定する方法です。
注意が必要なのが、1行目(row=0)で指定したコントロールの長さ(width) で格子のサイズが決められるという点です。
下記の例では、1行1列名(row=0,column=0)にラベルを表示していますが、このため1列目の幅は他の列にくらべてかなり狭くなっています。
columnspan は、そのコントロールで何列分を占有するかの指定で、下記の例では columnspan=2 なので、2列分を占有しています。
同様に rowspan により何行分を占有するかを指定することも可能です。
属性 | 説明 |
---|---|
column | 配置する列番号 |
columnspan | 何列にわたって配置するかの指定。初期値は1。 |
padx | 外側のX方向の余白を指定。 |
pady | 外側のY方向の余白を指定。 |
ipadx | 内側のX方向の余白を指定。 |
ipady | 内側のY方向の余白を指定。 |
row | 配置する行番号 |
rowspan | 何行にわたって配置するかのしh亭。初期値は 1。 |
sticky | pack の anchor と fill をあわせた属性。 スペースに余裕がある場合、どこに配置し、どのように引き伸ばすかを指定。 anchor と同じ指定だが、引き伸ばす場合はアンカー位置を+で結ぶ。 例:左右に引き伸ばす=tk.W + tk.E 上下に引き伸ばす=tk.N + tk.S, 全体(上下左右)に引き伸ばす=tk.W + tk.E + tk.N + tk.S。 |
place による配置
place は左端を原点(0,0)としたXY座標の指定でコントロールを配置する方法です。
ドット単位で座標を指定するため、位置決めは少々面倒ではありますが、他の配置方法に比べて癖がないため、一番扱いやすいかもしれません。
ただ、
属性 | 説明 |
---|---|
anchor | pack と同じ、初期値= Tk.NW |
bordermode | 縁を内側 (Tk.INSIDE) と外側(Tk.OUTSIDE)のどちらに付けるかを指定。 初期値= Tk.INSIDE |
height | 高さを pixel で指定。 |
relheight | 親に対する相対的な高さを0.0~1.0 の実数で指定。 |
relwidth | 親に対する相対的な幅を0.0~1.0の実数で指定。 |
relx | 親に対する相対的なX方向の位置を0.0~1.0の実数で指定。デフォルトは 0 |
rely | 親に対する相対的なY方向の位置を0.0~1.0 の実数で指定。デフォルトは 0 |
width | 幅をpixelで指定。 |
x | X方向の位置を pixel で指定。 |
y | Y方向の位置を pixel で指定。 |
イベントハンドラ
コントロールに、マウスクリックやキー入力、項目選択などのイベントが送られた時、それを処理するためのイベントハンドラ(関数)を指定することが可能です。
方法は2通りあって、1つはコントロールの command 引数に関数を指定する方法、もう1つは bind メソッドに関数を指定する方法です。
command 引数を使う
command 引数で指定したイベントハンドラは、そのコントロールが持つ代表的なイベント(ボタンの場合はマウス左クリック時、コンボボックスは項目選択時)が発生した際に呼び出されます。
下記はテキストボックスと「実行」ボタンという2つのコントロールが配置されており、「実行」ボタンをクリックすると、myfunc を呼び出す場合の例です。
1 2 3 4 5 6 |
#イベントハンドラ def myfunc(event): textbox.insert(0,'完了しました') #ボタンの生成 button = tk.Button(text='実行',width=10,command=myfunc) |
注意点としては、イベントハンドラには event という引数がありますが、コントロールによって引数の有無が変わってきます。
多くのコントロールの場合、イベントハンドラが呼ばれた時に、そのイベントに付随する情報が引数として渡される仕様になっていますが、スピンボックス、チェックボックス、メニューなど一部のコントロールは、引数が渡されません。
bind メソッドを使う
bind メソッドの第1引数にイベントの種類、第2引数にイベントハンドラを指定します。
command 引数の場合に比べて、より多くのイベントに対応することが可能です。
下記は、先ほどのソースコードにおいて、イベントハンドラの指定に bind を使った例です。
tk.Button で取得した button オブジェクトのbind メソッドを使ってイベントハンドラを指定していることろがポイントです。
1 2 3 4 5 6 7 8 9 |
#イベントハンドラ def myfunc(event): textbox.insert(0,'完了しました') #ボタンの生成 button = tk.Button(text='実行',width=10) #イベントハンドラの登録 button.bind('<Button-1>',myfunc) |
下記は一般的なイベントです。
bind に指定する際は、前後を '<' '>' で囲います。
例: xxxx.bind('<ButtonPress>',myfunc')
イベント名 | 内容 |
---|---|
KeyPress | フォーカスされた状態でキーが押された |
KeyRelease | フォーカスされた状態でキーが離された |
ButtonPress | マウスのボタンが押された |
ButtonRelease | マウスのボタンが離された |
Motion | マウスが移動した |
Enter | マウスがコントロール上に入った |
Leave | マウスが コントロール から離れた |
FocusIn | コントロール にフォーカスが合わされた |
FocusOut | コントロール からフォーカスが離れた |
Expose | 画面に表示された(レイアウト変更の反映含む) |
Visibility | 画面に表示された |
Destroy | コントロール が終了した |
Unmap | コントロール の配置が取り消された |
Map | コントロール が配置された |
Configure | コントロール の設定が変更された |
Activate | コントロール が有効化された |
Deactivate | コントロール が無効化された |
MouseWheel | マウスホイールが操作された |
イベントハンドラのラムダ式指定
command 引数の使用、bind メソッドの使用のどちらにおいても、イベントハンドラでラムダ式を使う事ができますが、少しだけ注意が必要です。
まず、イベントハンドラ(関数)は名前だけを指定しなければなりません。
もし、イベントハンドラに引数を渡したい場合は、ラムダ式(lambda)を使います。
1 2 3 4 5 6 7 8 9 10 11 |
#イベント引数 以外にも引数が必要なイベントハンドラの例 def myfunc(event,msg): #テキストボックスの中身を置き換える textbox.delete(0,tk.END) textbox.insert(0,msg) #イベント発生時、イベントハンドラにイベント引数が渡される場合 button = tk.Button(text='ボタン',command=lambda e : myfunc(e,'ABC')) #イベント発生時、イベントハンドラにイベント引数が渡されない場合 chkbox = tk.Checkbutton(text='チェック', variable=val,command=lambda : myfunc(None,'ABC')) |
ラムダ式の記述を忘れると、コントロールが生成されるタイミングでイベントハンドラが呼び出されてしまいますのでご注意ください。
パッケージの構成
Tkinter は複数のコンポーネントで構成されており、使うコントロールによって import すべきものが異なります。
import tkinter as tk でインポートしたからと言って、tk.Combobox や Spinboxが使えるわけではなく、別途 import tkinter.ttk as ttk をする必要があることに注意しましょう。
本記事で紹介するコントロールを使う場合、下記をimport しておく必要があります。
1 2 3 4 |
import tkinter.ttk as ttk import tkinter as tk import tkinter.scrolledtext as st import PIL.ImageTk as itk |
まとめ
今回は Tkinter を使ってWindowsのGUIを作成することを前提に、最初に知っておくべき前提知識について解説しました。
- TKinter は ルートのWindow、Frame、コントロールの3種類のオブジェクトを使ってGUIを構成しますが、それぞれに親子関係を持たせることで、階層をもったGUIの作成が可能。
- Frameやコントロールを配置する方法として、pack,grid,place の3種類が用意されており、それぞれの特徴に合わせて画面配置を行う。
- マウスクリック、ドラッグ、選択、キー入力などのイベントが発生した時のハンドラ(関数やメソッド)は、各コントロールのcommand 引数か、bind メソッドを使って定義する。
というところがポイントになります。
本記事の内容を理解しておくと Tkinter公式サイト から必要な情報だけ読み取って、自作プログラムに応用できると思いますので、是非ご活用下さい。
コメント