【Python】オプションメニューを使った処理の制御【Tkinter】

Python,Tkinter

オプションメニューを使った処理の制御

Tkinterでオプションメニューを使った処理の制御をする


値を取得する

ウィジェット変数

ウィジェット変数とは

  • ウィジェットの状態を制御するために使用されるオブジェクト
  • ウィジェットが表示される際に、ウィジェット変数に格納された値がウィジェットに反映される
  • ユーザーがウィジェットを操作した場合、その変更がウィジェット変数にも反映される

よく使われるウィジェット変数

  • StringVar:文字列を保持
  • IntVar:整数を保持
  • DoubleVar:浮動小数点を保持
  • BooleanVar:真偽値を保持

選択しているメニューの値を取得する

import tkinter as tk

# --------------------
# 値を取得する関数
# --------------------
def get_selected_value() -> None:
    selected_value = optionmenu_var.get()
    print(f'取得値:{selected_value}')

# GUIの基本設定
app = tk.Tk()
app.title('オプションメニューの設定値を取得')
app.geometry('350x200')

# オプションメニューの値を保持する変数と初期値の設定
optionmenu_var = tk.StringVar(value='未選択')

# オプションメニューの作成
optionmenu = tk.OptionMenu(
    app,
    optionmenu_var,
    'メニュー1',
    'メニュー2',
    'メニュー3',
)
optionmenu.pack(anchor='center', padx=20, pady=5)

# 関数を実行するボタン
btn = tk.Button(app, text='値を取得する', command=get_selected_value)
btn.pack(pady=40)

# アプリの実行
app.mainloop()

起動画面

任意のメニューを選択して値を取得する

実行結果

取得値:メニュー3

CustomTkinter版

import customtkinter as ctk

# --------------------
# 値を取得する関数
# --------------------
def get_selected_value() -> None:
    selected_value = optionmenu_var.get()
    print(f'取得値:{selected_value}')

# GUIの基本設定
app = ctk.CTk()
app.title('オプションメニューの設定値を取得')
app.geometry('350x200')

# オプションメニューの値を保持する変数と初期値の設定
optionmenu_var = ctk.StringVar(value='未選択')

# オプションメニューの作成
optionmenu = ctk.CTkOptionMenu(
    app,
    values=[
        'メニュー1',
        'メニュー2',
        'メニュー3',
        ],
    variable=optionmenu_var,
)
optionmenu.pack(anchor='center', padx=20, pady=5)

# 関数を実行するボタン
btn = ctk.CTkButton(master=app, text='値を取得する', command=get_selected_value)
btn.pack(pady=40)

# アプリの実行
app.mainloop()

起動画面

任意のメニューを選択して値を取得する

実行結果

取得値:メニュー3


メニューを選択した時に値を取得する

import tkinter as tk

# -----------------------------------
# メニュー選択時に値を取得する関数
# -----------------------------------
def optionmenu_callback(choice) -> None:
    print('メニュー選択で取得した値:', choice)

# -----------------------------------
# ボタンから値を取得する関数
# -----------------------------------
def get_selected_value() -> None:
    selected_value = optionmenu_var.get()
    print(f'ボタン押下で取得した値:{selected_value}')

# GUIの基本設定
app = tk.Tk()
app.title('オプションメニューの設定値を取得')
app.geometry('350x200')

# オプションメニューの値を保持する変数と初期値の設定
optionmenu_var = tk.StringVar(value='未選択')

# オプションメニューの作成
optionmenu = tk.OptionMenu(
    app,
    optionmenu_var,
    'メニュー1',
    'メニュー2',
    'メニュー3',
    command=optionmenu_callback  # メニュー選択の都度関数を実行する
)
optionmenu.pack(anchor='center', padx=20, pady=5)

# 関数を実行するボタン
btn = tk.Button(app, text='値を取得する', command=get_selected_value)
btn.pack(pady=40)

# アプリの実行
app.mainloop()

起動画面

任意のメニュー選択結果(1 → 2 → 3の順に選択)

メニュー選択で取得した値: メニュー1
メニュー選択で取得した値: メニュー2
メニュー選択で取得した値: メニュー3

ボタン押下による実行結果

ボタン押下で取得した値:メニュー3

CustomTkinter版

import customtkinter as ctk

# -----------------------------------
# メニュー選択時に値を取得する関数
# -----------------------------------
def optionmenu_callback(choice) -> None:
    print('メニュー選択で取得した値:', choice)

# -----------------------------------
# ボタンから値を取得する関数
# -----------------------------------
def get_selected_value() -> None:
    selected_value = optionmenu_var.get()
    print(f'ボタン押下で取得した値:{selected_value}')

# GUIの基本設定
app = ctk.CTk()
app.title('オプションメニューの設定値を取得')
app.geometry('350x200')

# オプションメニューの値を保持する変数と初期値の設定
optionmenu_var = ctk.StringVar(value='未選択')

# オプションメニューの作成
optionmenu = ctk.CTkOptionMenu(
    app,
    values=[
        'メニュー1',
        'メニュー2',
        'メニュー3',
        ],
    variable=optionmenu_var,
    command=optionmenu_callback # メニュー選択の都度関数を実行する
)
optionmenu.pack(anchor='center', padx=20, pady=5)

# 関数を実行するボタン
btn = ctk.CTkButton(master=app, text='値を取得する', command=get_selected_value)
btn.pack(pady=40)

# アプリの実行
app.mainloop()

起動画面

任意のメニュー選択結果(1 → 2 → 3の順に選択)

メニュー選択で取得した値: メニュー1
メニュー選択で取得した値: メニュー2
メニュー選択で取得した値: メニュー3

ボタン押下による実行結果

ボタン押下で取得した値:メニュー3


メニューの更新

メニューの選択内容で別メニューの選択肢を変える

  • 都道府県メニュー の選択内容で 市区町村メニュー の選択肢が変わるサンプル
  • TkinterのOptionMenuは業務に不向きなのでComboboxを使用している
  • アプリ実行前に同期処理をしておかないと市区町村メニューが空欄で起動してしまうので注意
import tkinter as tk
from tkinter import ttk

# ---------------------------------------------
# メニューAの選択でメニューBの内容を更新する
# ---------------------------------------------
PREF_TO_CITIES = {
    '東京都': ['千代田区', '新宿区', '渋谷区'],
    '神奈川県': ['横浜市', '川崎市', '相模原市'],
    '大阪府': ['大阪市', '堺市', '吹田市'],
}

def on_pref_changed(_event=None) -> None:
    selected_pref = pref_var.get()
    cities = PREF_TO_CITIES.get(selected_pref, [])

    # Bの候補を差し替え
    city_menu['values'] = cities

    # 候補があれば先頭、なければブランクにする
    if cities:
        city_var.set(cities[0])
        city_menu.current(0)
    else:
        city_var.set('')
        city_menu.set('')  # 表示も空にする

# GUIの基本設定
app = tk.Tk()
app.title('オプションメニューの設定値による制御')
app.geometry('350x200')
# 2列目を伸縮させる
app.grid_columnconfigure(1, weight=1)

# メニューA:都道府県
pref_var = tk.StringVar(value='東京都')
pref_menu = ttk.Combobox(
    app,
    textvariable=pref_var,
    values=list(PREF_TO_CITIES.keys()),
    state='readonly',  # 手入力を禁止
)

# 都道府県ラベル
label_pref = ttk.Label(app, text='【都道府県】')

# メニューB:市区町村
city_var = tk.StringVar()
city_menu = ttk.Combobox(
    app,
    textvariable=city_var,
    values=[],
    state='readonly',
)

# 市区町村ラベル
label_city = ttk.Label(app, text='【市区町村】')

# グリッド1行目に配置
label_pref.grid(row=0, column=0, padx=12, pady=(24, 16), sticky='w')
pref_menu.grid(row=0, column=1, padx=12, pady=(24, 16), sticky='ew')

# グリッド2行目に配置
label_city.grid(row=1, column=0, padx=12, pady=16, sticky='w')
city_menu.grid(row=1, column=1, padx=12, pady=16, sticky='ew')

# 変更イベント(選択が変わったとき)
pref_menu.bind('<>', on_pref_changed)

# 初期同期でメニューBを埋めておく
on_pref_changed()

# アプリの実行
app.mainloop()

起動画面

都道府県メニューを選択すると市区町村メニューが変化する

東京都選択時

神奈川県選択時

CustomTkinter版

import customtkinter as ctk

# ---------------------------------------------
# メニューAの選択でメニューBの内容を更新する
# ---------------------------------------------
PREF_TO_CITIES = {
    '東京都': ['千代田区', '新宿区', '渋谷区'],
    '神奈川県': ['横浜市', '川崎市', '相模原市'],
    '大阪府': ['大阪市', '堺市', '吹田市'],
}

def on_pref_changed(selected_pref: str) -> None:
    cities = PREF_TO_CITIES.get(selected_pref, [])

    # Bの候補を差し替え
    city_menu.configure(values=cities)

    # 候補があれば先頭、なければブランクにする
    if cities:
        city_var.set(cities[0])
    else:
        city_var.set('')

# GUIの基本設定
app = ctk.CTk()
app.title('オプションメニューの設定値による制御')
app.geometry('350x200')
# 2列目を伸縮させる
app.grid_columnconfigure(1, weight=1)

# メニューA:都道府県
pref_var = ctk.StringVar(value='東京都')
pref_menu = ctk.CTkOptionMenu(
    app,
    values=list(PREF_TO_CITIES.keys()),
    variable=pref_var,
    command=on_pref_changed,   # 変更時に呼ばれる(選択した都道府県を渡す)
)

# 都道府県ラベル
label_pref = ctk.CTkLabel(app, text='【都道府県】')

# メニューB:市区町村(初期は東京都に合わせる)
city_var = ctk.StringVar()
city_menu = ctk.CTkOptionMenu(
    app,
    values=[],
    variable=city_var
)

# 市区町村ラベル
label_city = ctk.CTkLabel(app, text='【市区町村】')

# グリッド1行目に配置
label_pref.grid(row=0, column=0, padx=12, pady=(24, 16), sticky='w')
pref_menu.grid(row=0, column=1, padx=12, pady=(24, 16), sticky='ew')

# グリッド2行目に配置
label_city.grid(row=1, column=0, padx=12, pady=16, sticky='w')
city_menu.grid(row=1, column=1, padx=12, pady=16, sticky='ew')

# 初期同期でメニューBを埋めておく
on_pref_changed(pref_var.get())

# アプリの実行
app.mainloop()

起動画面

都道府県メニューを選択すると市区町村メニューが変化する

東京都選択時

神奈川県選択時