Tkinter OptionMenu チュートリアル
Tkinter で OptionMenu を使ってドロップダウンを構築する方法を学びます。コールバック、ライブ更新、オプションの追加/削除、スタイルのコツ、および完全に実行可能なテーマ選擇示例を収録。
チュートリアルの進捗
1 Tkinter OptionMenu の概要
Tkinter の OptionMenu は、変数にバインドされたドロップダウンリストを作成します。テーマ、言語、または有限な選択肢のセットの選択に便利です。内部的には、選択された値を変数に格納し、ユーザーが新しい項目を選択するたびに関数を呼び出すことができます。
このガイドの終わりには、プレビューペインを更新し、選択されたテーマのメッセージを表示する、実行可能なテーマセレクターアプリが作成できるようになります。
2 前提条件: Python と Tkinter
Python 3.7 以降が必要です。Tkinter は macOS および Windows のほとんどの Python インストールに含まれています。Linux の場合は、tk パッケージをインストールしてください。
# Debian/Ubuntu
sudo apt-get install python3-tk
Tkinter が利用可能であることを確認してください。
python -m tkinter
小さなウィンドウが開けば、Tkinter は動作しています。
3 最小限の OptionMenu: コアパーツ
3 つの構成要素が必要です。Tkinter 変数 (通常は StringVar)、オプションのリスト、および変数に接続された OptionMenu です。
import tkinter as tk
root = tk.Tk()
root.title("Minimal OptionMenu")
# 1) 現在の選択を保持する変数
choice = tk.StringVar(value="A")
# 2) OptionMenu を作成し、変数とオプションを渡す
menu = tk.OptionMenu(root, choice, "A", "B", "C")
menu.pack(padx=20, pady=20)
root.mainloop()
- StringVar は、ドロップダウンと現在の値を同期させます。
value="A"はデフォルトを設定します。指定しない場合、通常は最初のオプションが選択されます。choice.set("B")を更新すると、OptionMenu の選択がプログラムで変更されます。
4 変更に反応する: コールバックを追加する
command 引数に関数を渡します。Tkinter は、新しく選択された値とともにそれを呼び出します。
import tkinter as tk
from tkinter import messagebox
def on_select(value):
messagebox.showinfo("Selection", f"You picked: {value}")
root = tk.Tk()
choice = tk.StringVar(value="Ocean")
menu = tk.OptionMenu(root, choice, "Ocean", "Forest", "Sunset", command=on_select)
menu.pack(padx=20, pady=20)
root.mainloop()
コールバックを使用して、他のウィジェットを同期したり、検証をトリガーしたり、情報パネルを更新したりします。
5 ライブプレビューを構築する (例のように)
テーマデータを格納し、選択が変更されるたびにプレビューペインを更新します。
import tkinter as tk
from tkinter import messagebox
themes = {
"Ocean": {"primary": "#1a73e8", "secondary": "#4285f4", "text": "white"},
"Forest": {"primary": "#2e7d32", "secondary": "#4caf50", "text": "white"},
"Sunset": {"primary": "#d32f2f", "secondary": "#f44336", "text": "white"},
}
def update_preview(theme_name):
t = themes[theme_name]
preview.configure(bg=t["primary"])
title.configure(bg=t["primary"], fg=t["text"])
button.configure(bg=t["secondary"], fg=t["text"], activebackground=t["primary"], activeforeground=t["text"])
root = tk.Tk()
choice = tk.StringVar(value="Ocean")
menu = tk.OptionMenu(root, choice, *themes.keys(), command=lambda v: update_preview(v))
menu.pack(padx=20, pady=10)
preview = tk.Frame(root, width=220, height=120, relief="raised", bd=2)
preview.pack(pady=10)
title = tk.Label(preview, text="Theme Preview")
title.pack(pady=6)
button = tk.Button(preview, text="OK", command=lambda: messagebox.showinfo("Theme", f"{choice.get()}"))
button.pack(pady=6)
update_preview(choice.get())
root.mainloop()
6 オプションの変更と項目の無効化
OptionMenu には、組み込みの削除/追加 API がありません。一般的なアプローチは、更新されたオプションでメニューを再構築し、現在の選択を保持することです。
def rebuild_options(new_options, keep_value=True):
current = choice.get() if keep_value else new_options[0]
menu["menu"].delete(0, "end")
for opt in new_options:
menu["menu"].add_command(label=opt, command=lambda v=opt: choice.set(v))
choice.set(current)
# これらから開始
choices = ["A", "B", "C"]
choice = tk.StringVar(value="B")
menu = tk.OptionMenu(root, choice, *choices)
menu.pack(padx=20, pady=20)
# 後で "B" を削除する
rebuild_options([opt for opt in choices if opt != "B"])
特定の項目を無効にするには、それをカスケードサブメニューで囲み、state="disabled" を使用します。削除や並べ替えは、再構築でより簡単に行えます。
7 スタイリングとレイアウト: 外観を整える
configure(width=...) を使用して幅を制御します。フォントと色については、メニューとその内部メニューウィジェットに属性を設定します。ttk.Frame と tk.OptionMenu を組み合わせることで、間隔を整理できます。
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
frame = ttk.Frame(root, padding=16)
frame.pack()
choice = tk.StringVar(value="Ocean")
menu = tk.OptionMenu(frame, choice, "Ocean", "Forest", "Sunset")
menu.configure(width=14, font=("Helvetica", 11))
menu["menu"].configure(font=("Helvetica", 11))
ttk.Label(frame, text="Choose a theme:").pack(anchor="w", pady=(0, 6))
menu.pack(anchor="w")
root.mainloop()
8 一般的な落とし穴と注意点
- 初期値を設定しないと、選択が空になる可能性があります。
- コールバックは変数ではなく、新しい値を受け取ります。より広範な状態が必要な場合は、変数を使用してください。
- OptionMenu には直接的な「オプションを削除」API がありません。内部
menuウィジェットを介して再構築してください。 tkとttkを混在させると、微妙なスタイルの違いが生じる可能性があります。- 一部のシステムでは、プラットフォームのレンダリングにより、内部メニューのフォントの変更が効果がない場合があります。
9 演習: オプションの追加と削除
最小限の例を拡張してください。エントリーフィールドと、入力されたオプションをメニューに挿入する (存在しない場合) ボタンを追加し、それを選択します。次に、現在選択されているオプションを削除する別のボタンを追加します。
import tkinter as tk
root = tk.Tk()
choice = tk.StringVar(value="A")
options = ["A", "B", "C"]
menu = tk.OptionMenu(root, choice, *options)
menu.pack(padx=16, pady=16)
entry = tk.Entry(root)
entry.pack(padx=16)
def add_option():
val = entry.get().strip()
if not val or val in options:
return
options.append(val)
menu["menu"].add_command(label=val, command=lambda v=val: choice.set(val))
choice.set(val)
def remove_selected():
val = choice.get()
if val not in options:
return
options.remove(val)
rebuild_options()
tk.Button(root, text="Add", command=add_option).pack(pady=6)
tk.Button(root, text="Remove Selected", command=remove_selected).pack(pady=6)
def rebuild_options():
current = choice.get()
menu["menu"].delete(0, "end")
for opt in options:
menu["menu"].add_command(label=opt, command=lambda v=opt: choice.set(v))
if options:
choice.set(current if current in options else options[0])
root.mainloop()
10 完全なプロジェクト: プレビュー付きテーマセレクター
これを theme_selector.py という名前のファイルにコピーし、python theme_selector.py で実行してください。
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
class ColorThemeSelector(tk.Tk):
def __init__(self):
super().__init__()
# メインウィンドウの設定
self.title("OptionMenu Example")
self.geometry("400x300")
self.configure(padx=20, pady=20)
# カラーテーマの定義
self.color_themes = {
"Ocean": {"primary": "#1a73e8", "secondary": "#4285f4", "text": "white"},
"Forest": {"primary": "#2e7d32", "secondary": "#4caf50", "text": "white"},
"Sunset": {"primary": "#d32f2f", "secondary": "#f44336", "text": "white"},
"Lavender": {"primary": "#7b1fa2", "secondary": "#9c27b0", "text": "white"}
}
# フレームの作成と設定
self.main_frame = ttk.Frame(self)
self.main_frame.pack(expand=True, fill='both')
# 選択されたオプションを格納する StringVar を作成
self.selected_theme = tk.StringVar()
self.selected_theme.set("Ocean") # デフォルト値を設定
# ラベルの作成
self.label = ttk.Label(
self.main_frame,
text="Select Your Color Theme:",
font=('Helvetica', 12)
)
self.label.pack(pady=10)
# OptionMenu の作成
self.theme_menu = tk.OptionMenu(
self.main_frame,
self.selected_theme,
*self.color_themes.keys(),
command=self.update_preview
)
self.theme_menu.configure(width=15)
self.theme_menu.pack(pady=10)
# プレビューフレームの作成
self.preview_frame = tk.Frame(
self.main_frame,
width=200,
height=100,
relief="raised",
bd=2
)
self.preview_frame.pack(pady=20)
# プレビュー要素の作成
self.preview_title = tk.Label(
self.preview_frame,
text="Theme Preview",
font=('Helvetica', 10)
)
self.preview_title.pack(pady=5)
self.preview_button = tk.Button(
self.preview_frame,
text="Sample Button",
command=self.show_selection
)
self.preview_button.pack(pady=10)
# プレビューの初期化
self.update_preview()
def update_preview(self, *args):
"""選択されたテーマの色でプレビューフレームを更新する"""
theme = self.color_themes[self.selected_theme.get()]
# プレビューフレームの背景を更新
self.preview_frame.configure(bg=theme["primary"])
self.preview_title.configure(
bg=theme["primary"],
fg=theme["text"]
)
self.preview_button.configure(
bg=theme["secondary"],
fg=theme["text"],
activebackground=theme["primary"],
activeforeground=theme["text"]
)
def show_selection(self):
"""現在の選択肢を示すメッセージボックスを表示する"""
messagebox.showinfo(
"Selected Theme",
f"You have selected the {self.selected_theme.get()} theme!"
)
if __name__ == "__main__":
app = ColorThemeSelector()
app.mainloop()
実行: python theme_selector.py。テーマを変更してみてください。プレビューがリアルタイムで更新されるのを確認してください。