このページでは、Tkinter における「フレーム」ウィジェットの使い方やフレームを利用するメリット、設定方法について説明します。
フレームとは
フレームは、一言でいうと複数のウィジェットをグループ化する「枠」です。
フレームも他のウィジェット同様に、メインウィンドウ上に作成・配置するウィジェットになります。
ただし、フレームは作成・配置しただけではあまり意味がなく、他のウィジェットをグループ化することで効果を発揮します。
メインウィンドウ上にウィジェットの作成・配置を行うことができることは皆さんもご存知だと思いますが、tkinter では、”フレーム自体にも” 他のウィジェットの作成・配置を行うことができます。
そして、同じフレーム上に作成・配置されたウィジェットを同じグループのウィジェットとして扱うことができます。つまり、フレームごとにグループが存在することになります。
さらに、フレームは名前の通り「枠」で、フレーム上のウィジェットは全てその枠の中に配置されることになります。また、それぞれのグループ間で独立してウィジェットの配置が行われます。それぞれで独立しているので、各グループをアプリの部品として扱いやすいです。
このフレームを用いるメリットは下記の3つです。
- レイアウトが楽になる
- グループ単位で一括で処理を実行することができる
- アプリの部品化がしやすい
この辺りのメリットについては、フレームウィジェットを利用するメリットで解説させていきたいと思います。
フレームウィジェットの作り方・使い方
フレームウィジェットは下記を実行することで生成することができます。
- Tkinter の
Frame
クラスのインスタンスを生成する
フレームウィジェットを生成するスクリプト例は下記のようになります。
# -*- coding:utf-8 -*-
import tkinter
# メインウィンドウを作成
app = tkinter.Tk()
# メインウィンドウ上にフレームを作成
frame1 = tkinter.Frame(
app,
width=300,
height=200
)
# フレームを配置
frame1.grid(column=0,row=0)
# メインループ
app.mainloop()
実行すると下の図のような画面のアプリが起動します。
ってメインウィンドウ上に何も見えませんね…。
フレームとは基本的にはそういうものです。ウィジェットをグループ化するのがメインの機能なので、ユーザーからは見えないようになっています(設定を変更することで見えるようにすることもできます)。
ただ、上記のスクリプトだとフレームの良さやフレームを使う意味が分からないと思いますので、次はその辺りが分かりやすいようなスクリプトを紹介したいと思います。
# -*- coding:utf-8 -*-
import tkinter
# メインウィンドウを作成
app = tkinter.Tk()
app.geometry("400x350")
# メインウィンドウ上にフレームを作成
frame1 = tkinter.Frame(
app,
)
frame2 = tkinter.Frame(
app,
)
# frame1上にウィジェットを作成
canvas = tkinter.Canvas(
frame1,
width=300,
height=300,
bg="blue"
)
canvas.pack()
button1 = tkinter.Button(
frame1,
text="ボタン1",
)
button1.pack()
# frame2上にウィジェットを作成
label = tkinter.Label(
frame2,
text="ラベル"
)
label.pack()
button2 = tkinter.Button(
frame2,
text="ボタン2"
)
button2.pack()
# フレームを配置
frame1.grid(column=0,row=0)
frame2.grid(column=1,row=0)
# メインループ
app.mainloop()
実行すると下の図のような画面のアプリが起動します。
今回はなんとなーくフレームの効果が確認できるのではないかと思います。
ということで、このスクリプトを用いてフレームの作り方について解説していきたいと思います。
スポンサーリンク
メインウィンドウの作成とメインループ
まずスクリプトの下記部分ではメインウィンドウ作成とメインループの実行を行なっています。
# メインウィンドウを作成
app = tkinter.Tk()
app.geometry("400x350")
# 〜略〜
# メインループ
app.mainloop()
この辺りは他のウィジェットと同様ですね!ここでは詳しく解説しませんが、メインウィンドウについては下記で、
Tkinterの使い方:メインウィンドウを作成するメインループについては下記で解説していますので詳しく知りたい方はこれらのページを参考にしていただければと思います。
【Python】tkinterのmainloopについて解説フレームウィジェットの作成(Frame()
)
フレームウィジェットを実際に作成しているのは下記になります。tkinter.Frame
クラスのインスタンスを生成しており、これによりフレームウィジェットが作成されます。
# メインウィンドウ上にフレームを作成
frame1 = tkinter.Frame(
app,
)
frame2 = tkinter.Frame(
app,
)
第1引数に指定するのは、フレームウィジェットの親ウィジェットになります。
今回はメインウィンドウのオブジェクトである app
を指定していますが、他のフレームウィジェットを指定するようなことも可能です。
つまりフレームウィジェットは重ねて配置するようなことが可能です。
また、今回は Frame
には第1引数しか指定していませんが、キーワード引数でウィジェットの設定(オプション)を指定することも可能です。
具体的な設定可能なキーワード引数は後述のフレームウィジェットの設定で解説します。
フレーム上へのウィジェットの作成と配置
ここからが “フレームウィジェットならでは” の処理になってきます。
各ウィジェット作成時には、コンストラクタの第1引数に親ウィジェットを指定しますが、この指定が意味するのは、ウィジェットの作成先です。
つまり、ウィジェットは第1引数に指定したウィジェット上に作成・配置されることになります。
さらに、同じウィジェット上に作成されたウィジェットは同じグループのウィジェットとして扱われます。
で、フレームのメイン機能はこのグループ化なので、フレームはただ単に作成して配置しただけではあまり意味がなく、そのフレーム上にウィジェットを配置し、ウィジェットをグループ化したときに効果を発揮します。
なので、フレームを利用する際には、そのフレーム上に他のウィジェットを作成・配置する処理も合わせて記述する必要があります。
このフレーム上へのウィジェットの作成と配置を行なっているのが下記部分になります。
# frame1上にウィジェットを作成
canvas = tkinter.Canvas(
frame1,
width=300,
height=300,
bg="blue"
)
canvas.pack()
button1 = tkinter.Button(
frame1,
text="ボタン1",
command=removeFrame
)
button1.pack()
# frame2上にウィジェットを作成
label = tkinter.Label(
frame2,
text="ラベル"
)
label.pack()
button2 = tkinter.Button(
frame2,
text="ボタン2"
)
button2.pack()
各フレームに対して下記のようにウィジェットの作成と配置を行なっています。
frame1
:canvas
とbutton1
frame2
:label
とbutton2
ただし、フレーム上にウィジェットを作成して配置したとしても、この段階ではまだ画面には表示されません。
これはフレーム自体の配置をまだ行なっていないからです。
フレーム上に作成・配置されたウィジェットは、そのフレームが配置されて初めて画面に表示されることになります。
ということで次はフレームの配置を行なっていきましょう!
スポンサーリンク
フレームウィジェットの配置
下記ではフレームウィジェットの配置を行なっています。
# フレームを配置
frame1.grid(column=0,row=0)
frame2.grid(column=1,row=0)
上記では、grid
メソッドを利用して、2つのフレームを横に並べる形で配置しています。
フレームウィジェットにおいても、他のウィジェット同様に、配置には下記の3つのメソッドを利用することが可能です。
pack
grid
place
これらのメソッドについては下記ページで解説していますので、詳しく知りたい方はコチラを読んでいただければと思います。
Tkinterの使い方:ウィジェットの配置(pack・grid・place)前述の通り、このフレームの配置を行なった時に、フレーム上に作成・配置したウィジェットが画面に表示されることになります(厳密には配置した後に mainloop
を実行することで表示される)。
ちなみに、ウィジェットを配置していないフレームを配置した場合は画面上には見えません(フレームウィジェットの設定で説明する設定により見えるようにすることも可能)。
フレームウィジェットを利用するメリット
フレームウィジェットを利用する目的は「複数のウィジェットをグループ化する」ことです。
では、このグループ化することでどのようなメリットがあるのでしょうか?
前述でも述べましたが、このメリットは下記の3つになります。
- レイアウトが楽になる
- グループ単位で一括で処理を実行することができる
- アプリの部品化がしやすい
レイアウトが楽になる
まずウィジェットのレイアウトが楽になります。特にウィジェットの数が多い場合に便利です。
前述の通り、フレームはメインウィンドウ(や他のフレーム)上に配置可能な枠です。
また、フレームには他のウィジェットを pack
・grid
・place
で配置することが可能であり、それらのウィジェットはフレーム内に配置されることになります。
フレーム毎に個別の独立した空間が用意され、フレーム上のウィジェットはそれぞれの空間に配置される感じです。
さらに、このフレーム自体も他のウィジェット同様にメインウィンドウ上に pack
・grid
・place
メソッドを用いて配置することが可能です。
これらを利用すれば、フレームを利用することで下記のように2段階的にアプリ内のウィジェットのレイアウトを行うことができるようになります。
- まずフレームを配置してアプリのレイアウトの大枠を構成する
- 各フレームに対してウィジェットを配置してアプリの詳細なレイアウトを構成する
アプリ全体で全てのウィジェットの配置を細かく決めるのは、特にウィジェットの数が多いと大変です。
ですが、フレームを利用すれば、1. でアプリのレイアウトの大枠さえ構成してやれば、あとは 2. でフレーム単位でウィジェットの配置をすれば良いだけになるので、複雑なレイアウトでも簡単に行うことができます。
また、tkinter には、同じグループのウィジェット(親ウィジェットが同じウィジェット)の中では pack
での配置と grid
での配置を混在させることができないという決まりがあります。混在させると実行時にエラーになります。
ですが、グループ間では同じアプリ内であっても pack
と grid
を混在させることが可能です。つまり、フレームを複数用意して複数のグループを用意してやれば、同じアプリ内で pack
と grid
を混在させることができます。
この pack
と grid
の混在により、より複雑なレイアウトを place
なしで実現することができます。
スポンサーリンク
グループ単位で一括で処理を実行することができる
さらに、フレームウィジェットの作り方・使い方でも少し説明しましたが、フレーム上に配置したウィジェットは、フレームを配置した時に初めて画面に表示されることになります。
これを利用して、同じグループのウィジェット全ての表示・非表示を、フレームの表示・非表示のみで切り替えるようなこともできます。
この利用例が下記のスクリプトになります。
# -*- coding:utf-8 -*-
import tkinter
# フレーム2のremove中フラグ
is_removed = False
def removeFrame():
global frame2
global button2
global is_removed
if is_removed:
# remove中であれば再度gridで配置
frame2.grid()
is_removed = False
else:
# remove中でないならばremove
frame2.grid_remove()
is_removed = True
# メインウィンドウを作成
app = tkinter.Tk()
app.geometry("400x350")
# メインウィンドウ上にフレームを作成
frame1 = tkinter.Frame(
app,
)
frame2 = tkinter.Frame(
app,
)
# frame1上にウィジェットを作成
canvas = tkinter.Canvas(
frame1,
width=300,
height=300,
bg="blue"
)
canvas.pack()
button1 = tkinter.Button(
frame1,
text="ボタン1",
command=removeFrame
)
button1.pack()
# frame2上にウィジェットを作成
label = tkinter.Label(
frame2,
text="ラベル"
)
label.pack()
button2 = tkinter.Button(
frame2,
text="ボタン2"
)
button2.pack()
# フレームを配置
frame1.grid(column=0,row=0)
frame2.grid(column=1,row=0)
# メインループ
app.mainloop()
このスクリプトを実行してボタン1をクリックすると、ラベルとボタン2の表示と非表示が切り替わることが確認できると思います。
上記スクリプトでは、ボタン1がクリックされた時に removeFrame
が実行されるようにしており、その removeFrame
では frame2
のみの表示と非表示の切り替えを行なっています(grid
と grid_remove
を交互に実行)。
つまり、フレームの表示と非表示の切り替えを行うだけで、そのフレーム上の全てのウィジェットの表示と非表示の切り替えを一括して行うことができています。
処理を行う対象のウィジェットが1つだけになるので、プログラミングが楽になります。
こんな感じで、複数のウィジェットに対して一括で処理を行いたいような場合にも、フレームによるグループ化が便利です。
アプリの部品化がしやすい
また、フレームを利用することでアプリの部品化がしやすいというメリットがあります。
例えば下の図のようなフレーム(とフレーム上のウィジェット)があるとしましょう。
さらに、例えばフレーム上のボタンが下記を行うとしましょう(かなり大雑把に書いてます)。
frame1
:- 数字:押された数字を記憶する
- 演算子:記憶した数字と押された演算子で計算を行う
frame2
:- 表示:画像を
Canvas
に描画する
- 表示:画像を
frame3
:- 表示:文字列を
Textbox
に表示する
- 表示:文字列を
frame4
:- 開く:ファイルを開く
- 保存:ファイルに保存する
これらの4つのフレームの組み合わせやメインウィンドウ上への配置位置を変更することで、さまざまなアプリを作成することができます。
例えば frame2
と frame4
をメインウィンドウ上に作成・配置してやれば、下の図のような画像ビューワーのようなアプリに仕立てるようなことができます。
また frame3
と frame4
をメインウィンドウ上に作成をメインウィンドウ上に作成・配置してやれば、下の図のようなテキストエディタのようなアプリに仕立てるようなことができます。
さらに frame3
と frame1
をメインウィンドウ上に作成・配置してやれば、下の図のような電卓のようなアプリに仕立てるようなことができます。
こんな感じで、フレーム単位でアプリの一部を作成していくことで、フレーム上のウィジェットのグループを部品として他のアプリに再利用したり、その部品を組み合わせることで新たなアプリを作成したりすることができます。
もちろん再利用したり組み合わせたりする際に各フレームやフレーム上のウィジェットを変更をする必要はあるかもしれませんが、それでもゼロベースでアプリを作成していくよりも効率は向上すると思います。
また、ウィジェット単体もアプリの部品と考えることができますが、複数のウィジェットをフレームでグループ化した状態で部品化できるので、ウィジェット単体よりも再利用時の開発効率が上がります。
特に、グループ単位でクラス化しておけば、あとはそのクラスのオブジェクトをメインウィンドウ上に配置するだけでアプリを作っていくことができるので便利です。クラス化はグループ単位で行いたいので、ウィジェットをグループ化することができる tkinter.Frame
を親クラスとしたクラスとして作成する必要があります。
例えばフレームウィジェットの作り方・使い方で紹介したスクリプトを、グループ単位でクラス化したスクリプトは下記のようになります。
# -*- coding:utf-8 -*-
import tkinter
class Frame1(tkinter.Frame):
def __init__(self, master):
super().__init__(master)
canvas = tkinter.Canvas(
self,
width=300,
height=300,
bg="blue"
)
canvas.pack()
button = tkinter.Button(
self,
text="ボタン1",
)
button.pack()
class Frame2(tkinter.Frame):
def __init__(self, master):
super().__init__(master)
label = tkinter.Label(
self,
text="ラベル"
)
label.pack()
button = tkinter.Button(
self,
text="ボタン2"
)
button.pack()
# メインウィンドウを作成
app = tkinter.Tk()
# 各部品オブジェクトを作成
frame1 = Frame1(app)
frame2 = Frame2(app)
# 部品を配置
frame1.grid(column=0,row=0)
frame2.grid(column=1,row=0)
# メインループ
app.mainloop()
Frame1
が元々のスクリプトにおける frame1
及びそのグループに属するウィジェットをまとめて部品化したクラスになります。Frame2
も同様です。
こんな感じでグループを部品化したクラスを用意していくことで、今後のアプリ開発が楽になります。
フレームウィジェットの設定
最後に、ウィジェットの作成時(tkinter.Frame()
実行時)や config
メソッド実行時にキーワード引数で指定するフレームウィジェットの設定について解説していきます。
設定できる全てのキーワードは下記により確認することができます。
# frameはFrameのインスタンス
print(frame.keys())
ここでは私がよく使うもの・動作を理解しているものをピックアップして説明していきたいと思います。
私の下記環境での実行結果をもとに説明していますが、環境によっては動きが異なるかもしれません
実際にご自身の環境で実行結果を確認していただくと、より確実に設定の効果を理解することができると思います
- OS:macOS Catalina
- Python:3.8
- Tkinter:8.6
スポンサーリンク
width
・height
width
と height
を指定することでフレームウィジェットの幅と高さを設定することができます。
この width
と height
には整数を指定します。単位はピクセルになります。
フレームの width
と height
をそれぞれ 300
px と 200
px に設定する例は下記のようになります。
frame = tkinter.Frame(
app,
width=300, # widthの設定
height=200, # heightの設定
)
ただし、私の環境では、フレーム上のウィジェットの配置に pack
や grid
を利用した場合は width
と height
設定が無視され、配置したウィジェットのサイズによって自動的に再設定されるようでした。
一方で、フレーム上のウィジェットの配置を place
で行う場合は、この width
と height
を設定しないと上手く配置できませんでした。
また place
実行時には、その width
と height
に収まるように x
と y
を設定する必要があります(外側に配置しても表示されない)。
上記の制限があるので、実質的に同じ Frame
内では pack
と place
や grid
と place
での配置の混在ができないことになります。
環境によって動作が異なるかもしれませんが、私の環境と同じ方(特に MacOSX を利用されている方)は上記の点に気をつけて width
と height
を指定していただければと思います。
bg
(or background
)
bg
もしくは backgroud
を指定することでフレームの背景色を設定することができます。
これらには色名の文字列やカラーコード等を指定することができます。
フレームに対する bg
の設定例は下記のようになります。
frame = tkinter.Frame(
app,
width=200,
height=200,
bg="green"
)
メインウィンドウの色と異なる色を設定することで、フレーム自体が目で確認できるようにすることができます。
bd
(or borderwidth
)
bd
もしくは borderwidth
を指定することでフレームの枠線の太さを設定することが可能です。
bd
もしくは borderwidth
には整数を指定します(単位はピクセル)。
フレームに対して bd
を 10
px に設定する例は下記のようになります。
frame = tkinter.Frame(
app,
width=200,
height=200,
bd=10, # bdの設定
)
ただ私の環境では枠線の太さを変更しても、そもそも枠線の色が背景の色と同じになっていて違いが確認できませんでした…。
次の relief
の設定を行うと bd
による枠線の太さの変化が分かりやすいと思います。
スポンサーリンク
relief
relief
を指定することでフレームの見た目を設定することができます。
relief
に指定可能なパラメータは下記の6つになります。
tkinter.RAISED
tkinter.SUNKEN
tkinter.FLAT
tkinter.RIDGE
tkinter.GROOVE
tkinter.SOLID
フレームに対する relief
の設定例は下記のようになります。
frame = tkinter.Frame(
app,
width=100,
height=100,
bd=20,
bd="gray",
relief=tkinter.RAISED, # reliefの設定
)
relief
の指定によって、フレームの見た目は下の図のように変わります。
relief
は枠線の描画方法を変更することでフレームの見た目を変更するものですので、枠線がないような場合は relief
を指定しても見た目が変わらないので注意してください。
padx
・pady
padx
・pady
の指定により、フレーム内の余白サイズを設定することができます。
padx
:左右の余白量(ピクセル単位)pady
:上下の余白量(ピクセル単位)
padx
と pady
の設定例は下記のようになります。
frame = tkinter.Frame(
app,
bd=10,
relief=tkinter.RAISED,
padx=100, # padxの設定
pady=30, # padyの設定
)
この frame
にボタンウィジェットを pack
で配置した場合のフレームの見た目は下の図のようになります。ボタンとフレームの枠線の間に左右上下方向に余白があることが確認できると思います。
ちなみに padx
と pady
を設定しなかった場合は下の図のようになります。
この2つの違いからも padx
と pady
の効果が確認できると思います。
cursor
cursor
を指定することでフレーム上にマウスカーソルが入ったときのカーソルの見た目(アイコン)を設定することができます。
例えば cursor
には下記のような値を設定することが可能です。
"hand"
"ibeam"
"wait"
"poof"
OS 毎に指定可能な値が異なる可能性が高いので注意してください。
フレームに対する cursor
の設定例は下記のようになります。
frame = tkinter.Frame(
app,
width=200,
height=200,
relief=tkinter.RAISED,
bd=10,
cursor="hand" # cursorの設定
)
これにより、フレーム上ではマウスカーソルが手の形に変化します。
スポンサーリンク
takefocus
takefocus
の指定により、タブキーによるフォーカスの有効無効を設定することができます。
ただ、フレームに対してフォーカスをあてる効果は正直よく分かりません…。
例えばスクロールバーであれば、フォーカスをあてれば方向キーでスライダーを移動させることができたりするのですが…
とりあえず解説を進めると、このフォーカスをあてられるかどうかを、takefocus
に下記のように指定すること設定することができます。
takefocus=0
:フォーカスがあてられないtakefocus=1
:フォーカスがあてられる
デフォルト設定は takefocus=0
になります。
frame = tkinter.Frame(
app,
width=200,
height=200,
takefocus=1, # takefocusの設定
)
highlightcolor
・highlightbackground
・highlightthickness
highlightcolor
・highlightbackground
・highlightthickness
の指定により、フレームにフォーカスがあてられた時&フォーカスが外れた時のフレームの囲い線の設定が可能です。
highlightcolor
:フォーカスがあてられた時の囲い線の色highlightbackground
:フォーカスが外れた時の囲い線の色highlightthickness
:囲い線の太さ(px)
下記はこれらのキーワードを指定するスクリプトの例になります。
frame = tkinter.Frame(
app,
width=200,
height=200,
highlightthickness=10, # highlightthicknessの設定
highlightbackground="blue", # highlightbackgroundの設定
highlightcolor="red", # highlightcolorの設定
takefocus=1
)
上記のフレームを配置したスクリプトを実行すると下の図のようなアプリが起動します。
青い線がフォーカスに対するフレームの囲い線になります。この囲い線の太さが、highlightthickness
で指定している 10
px になります。
また、現状このフレームにフォーカスが当たっていないので、この囲い線の色は highlightbackground
で指定している "blue"
になります。
この状態でタブキーを押してフレームにフォーカスをあてると、今度はこの囲い線の色が highlightcolor
で指定している "red"
に変化します。
まとめ
このページでは、tkinter でのフレームの作り方・使い方について解説し、その後フレームを利用するメリットとフレームウィジェットの設定について解説しました。
フレームを利用することで最初に感じるメリットはウィジェットの配置です。フレームを利用することで簡単に複雑なレイアウトのアプリを実現することができるようになります。
また、フレームを利用することでアプリを部品単位で扱いやすくなります。これによりアプリの開発効率を向上することができます。
ソフトウェアの部品化は、tkinter だけでなくさまざまな分野のソフトウェア開発に用いられる考え方なので、フレームの使い方だけでなく、このソフトウェアの部品化の考え方についても、この機会にしっかり理解しておきましょう!
オススメ参考書(PR)
Tkinter に興味がある方には下記のPythonでつくる ゲーム開発 入門講座がオススメです。
Tkinter をゲーム開発を通して「楽しく学ぶ」ことができます。Python 入門者、Tkinter 入門者の方にオススメです。
[…] (参考)Tkinterの使い方:フレームウィジェット(Frame) – だえう … […]