はじめに
メンテナンスツール(スクリプト)を数々作成したため、いちいちスクリプトファイルを選んで実行するのは面倒でした。そこで、TkinterによるSelect Launcherを作り、選択実行できるようにしました。
ボタンを作るたびに、その数分tk.Button宣言を記述していては、長々としたコードになってしまうので、lambda式を使用してコード量を減らします。
この時のlambda式の記述の仕方をメモに残しておきます。
lambda式
Python 公式ドキュメント
6.14. ラムダ (lambda)
lambda_expr ::= "lambda" [parameter_list] ":" expression
ラムダ式 (ラムダ形式とも呼ばれます) は無名関数を作成するのに使います。 式 lambda parameters: expression は関数オブジェクトになります。 この無名オブジェクトは以下に定義されている関数オブジェクト同様に動作します:
def <lambda>(parameters):
return expression
引数の一覧の構文は 関数定義 を参照してください。ラムダ式で作成された関数は文やアノテーションを含むことができない点に注意してください。
記述
最終的なソースコードは、後述します。
与えられた文字列リストselect_listをもとにボタンが縦に並びます。
for文での記述箇所は、以下の通りです。
for name in self.select_list:
btn = tk.Button(
root,
text=name,
command=lambda key=name: self.btn_clicked(key)
)
btn.pack(
side=tk.TOP, fill=tk.BOTH,
padx=sp, pady=sp, ipadx=sp, ipady=sp
)
ポイントは、lambda式の**key=name:**です。
これを以下のようにして、直接変数nameを与えるとどうなるでしょうか?
command=lambda self.btn_clicked(name)
このように記述すると、self.btn_clicked関数に渡される値は、全てFor分の最終結果である「name='C'」となってしまいます。
Select Dialog(Launcher)
文字列のリストを渡すと、以下のようなダイアログが表示されるプログラムです。
ソースコード(最終)
import tkinter as tk
class select_dialog():
def __init__(self, select_list: list) -> None:
self.select_list = select_list
self.create_dialog(self._tk_root_())
return
def _tk_root_(self) -> tk.Tk:
item = len(self.select_list)
screen_w, screen_h = 240, item*45
root = tk.Tk()
root.attributes('-topmost', True)
root.title(f'Select Menu')
geo_string = f'{screen_w}x{screen_h}'
root.geometry(geo_string)
root.lift()
root.focus_force()
return root
def create_dialog(self, root):
sp = 5
for name in self.select_list:
btn = tk.Button(
root,
text=name,
command=lambda key=name: self.btn_clicked(key)
)
btn.pack(
side=tk.TOP, fill=tk.BOTH,
padx=sp, pady=sp, ipadx=sp, ipady=sp
)
root.mainloop()
return
def btn_clicked(self, name):
print(name)
if __name__ == '__main__':
select_list = ['A', 'B', 'C']
select_dialog(select_list)