
Tkinterでウィジェットを作成・配置する際の階層構造の構成と、そのために使用するフレーム(Frame)ウィジェットについて解説します。あるべき構造を理解してから作り始めることで効率的な運用が見込めます。
目次
TkinterにおけるWidgetの階層構造

Tkinterではウィジェットは階層構造を構成するように作成します。
root要素にそのまま各ウィジェットを配置していくこともできますが、フレームで各ウィジェットをまとめてグループ化することでプログラムをフレーム単位でモジュール化することができ、フレームを乗せ換えることでアプリケーションの画面を切り替えることもできるようになります。
GUI画面では次のように表示されます。

フレーム(Frame)ウィジェットとは
フレーム自体はほとんど何をするわけでもありませんが、他のウィジェットをまとめて配置するためのコンテナとして働きます。
Frameインスタンスを作成する際は次のようなオプション引数を指定することができます。
| 属性 | 説明 | 値 |
|---|---|---|
| bg or background | 背景の色を指定します | red,blue,grayなど |
| bd or borderwidth | ボーダーの幅を指定します | ピクセル単位の数値 |
| relief | ボーダー部分の浮き彫りを指定します | flat,raised,sunken,groove,ridge |
| width | 幅をピクセル単位で指定します | ピクセル単位の数値 |
| height | 高さをピクセル単位で指定します | ピクセル単位の数値 |
Frame を作成する際は親ウィジェット(今回はルート要素)を指定します。
import tkinter as tk
root = tk.Tk()
# ウィンドウの設定
root.title("ウィンドウのタイトル")
root.geometry("400x300")
# フレームの作成
frame1 = tk.Frame( # frame1インスタンスを作成
root, # root要素であるウィンドウを指定
background="gray", # 背景色を指定
borderwidth=5, # ボーダーの幅を指定
relief="sunken", # ボーダーの浮き彫りを指定
width=400, # 幅をpixel単位で指定
height=300, # 高さをpixel単位で指定
)
frame1.pack() # frame1インスタンスを配置
root.mainloop() # イベントハンドラの呼び出し
上記のようなウィンドウが表示されます。
実際の例としてFrameウィジェットの中にLabel、Entry、Buttonを配置してみましょう。
先ほどのように手続き型で書いていくこともできますが、Tkinterを含めPythonのGUIプログラムは次のようにFrameの導出クラスを定義してオブジェクト指向で書くのが一般的です。
import tkinter as tk
# tk.Frameを継承したFrame1クラスを作成
class Frame1(tk.Frame):
def __init__(self, master=None): # コンストラクタを定義
super().__init__(master) # 継承元クラス(tk.Frame)のコンストラクタを呼び出し
#ウィンドウの設定
master.title("ウィンドウのタイトル")
master.geometry("400x300") # 幅と高さを指定
# フレームの設定
self.config(bg="whitesmoke") # 背景色を指定
self.propagate(False) # フレームのpropagate設定 (この設定がTrueだと内側のwidgetに合わせたフレームサイズになる)
# 実行内容
self.pack() # フレームを配置
self.create_widget() # 下記で定義しているcreate_widgetメソッドを実行
#create_widgetメソッドを定義
def create_widget(self):
# ラベルを作成
self.label1 = tk.Label(self.master, text=u"これはラベルです")
self.label1.pack()
# エントリーを作成
self.entry1 = tk.Entry(self.master)
self.entry1.insert(tk.END, u"これはエントリーです")
self.entry1.pack()
# ボタンを作成
button1 = tk.Button(self.master, text=u"これはボタンです")
button1.pack()
if __name__ == "__main__": # このファイルが実行されている場合の処理
root = tk.Tk() # rootインスタンスを生成
f1 = Frame1(master=root) # Frame1クラスからf1インスタンスを生成
f1.mainloop() # f1インスタンスのイベントハンドラを呼び出し
見た目上はラベル、エントリー、ボタンをそのまま配置したのと変わりませんが、このコードではそれらのウィジェットはFrame1という1つのフレームにまとめられているため効率的に管理・運用できます。
フレームを(Frame)入れ子にする
フレームを入れ子にすることで複雑なウィンドウを作ることができます。
次のコードではメインフレームの中にframe1とframe2という2つのフレームを含み、frame1とframe2はそれぞれ4つのラベルウィジェットを含んでいます。
import tkinter as tk
# tk.Frameを継承したApplicationクラスを作成
class Application(tk.Frame):
def __init__(self, master=None):
super().__init__(master, width=200, height=150)
# ウィンドウの設定
self.master.title("ウィンドウのタイトル")
# 実行内容
self.pack() # メインフレームを配置
self.create_widget() # create_widgetメソッドを実行
#create_widgetメソッドを定義
def create_widget(self):
# 1つ目のフレーム
frame1 = tk.Frame(self.master, relief=tk.RIDGE, bd=2) # tk.Frameクラスからframe1インスタンスを生成
list1 = [("A", "lightskyblue"), ("B", "khaki"), ("C", "yellowgreen"), ("D", "hotpink")] # list1リストを定義
for text, color in list1: # ループ開始
label=tk.Label(frame1, text=text, bg=color, font=("20")) # labelウィジェットを作成
label.pack(side=tk.LEFT) # labelウィジェットを配置
frame1.place(relx=0.1, rely=0.1) # frame1フレームを配置
# 2つ目のフレーム
frame2 = tk.Frame(self.master, relief=tk.RIDGE, bd=2) # tk.Frameクラスからframe2インスタンスを生成
list2 = [("A", "lightskyblue"), ("B", "khaki"), ("C", "yellowgreen"), ("D", "hotpink")] # list2リストを定義
for i, (text, color) in enumerate(list2): # ループ開始
label=tk.Label(frame2, text=text, bg=color, font=("20")) # labelウィジェットを作成
label.grid(row=i//2, column=i%2) # labelウィジェットを配置
frame2.place(relx=0.6, rely=0.5) # frame2フレームを配置
if __name__ == "__main__":
root = tk.Tk()
app = Application(master=root)
app.mainloop()
このようにTkinterの階層構造の構成を理解してFrameウィジェットを使いこなすことで、複雑なウィンドウ構成を実現することができます。







