ブログ

tkinterを使った複数個あるbindをloopで処理する方法

image

2024年11月3日

tkinter で複数個のボタンの配置

tkinterを使っていて、ボタンなど同じ物を複数個作成する際、1 つずつ作成していると面倒なので、`loop` を使って以下のような方法をとると思います。

import tkinter as tk


root = tk.Tk()
buttons = []
# 5つのボタンを追加
for i in range(0,5):
    buttons.append(tk.Button(root, text=f"{i}番目のボタン"))
    buttons[i].pack()

root.mainloop()

bind 処理の追加

ここに bind で右クリック処理を付けます。

import tkinter as tk
from tkinter import messagebox 


 # クリック関数 
 def click(event):
     messagebox.showinfo("情報", "クリックしました")
     return


root = tk.Tk()
buttons = []
# 5つのボタンを追加
for i in range(0, 5):
    buttons.append(tk.Button(root, text=f"{i}番目のボタン"))
    buttons[i].pack()
     # bind 処理追加 右クリックに処理を付ける 
     buttons[i].bind("<Button-3>", click)

root.mainloop()

ただ、これでは何番目のボタンをクリックしたかわかりません。

lambda 関数を使えば関数に引数を渡せるため上手くいきそうです。

import tkinter as tk
from tkinter import messagebox


# クリック関数
 def click(event):
     messagebox.showinfo("情報", "クリックしました")
     def click(event, i):
     messagebox.showinfo("情報", f"{i}をクリックしました")
return


root = tk.Tk()
buttons = []
# 5つのボタンを追加
for i in range(0, 5):
    buttons.append(tk.Button(root, text=f"{i}番目のボタン"))
    buttons[i].pack()
    # bind 処理追加 右クリックに処理を付ける
     # lambda 関数で引数を渡す 
     buttons[i].bind("<Button-3>", click)
     buttons[i].bind("<Button-3>", lambda event: click(event, i))
root.mainloop()

実行すると、確かに「4 をクリックしました」と表示されるので、値が送られています。ただ、どこを押しても「4 をクリックしました」となってしまいます。

これは、ボタンをクリックした際に i の値を参照するためで、(クリックするときは 5 つのボタンが作成された後であるため)i の値 4 がすべてのボタンで表示されてしまっています。

解消方法

この現象を回避するためにヘルパー関数を間に挟むことで解消できます。

import tkinter as tk
from tkinter import messagebox


# クリック関数
def click(event, i):
    messagebox.showinfo("情報", f"{i}をクリックしました")
    return


 # ヘルパー関数 
 def helper_lambda(i):
     return lambda event: click(event, i)


root = tk.Tk()
buttons = []
# 5つのボタンを追加
for i in range(0, 5):
    buttons.append(tk.Button(root, text=f"{i}番目のボタン"))
    buttons[i].pack()
    # bind 処理追加 右クリックに処理を付ける
     # lambda 関数で引数を渡す 
     # ヘルパー関数を通してクリック関数を呼び出す 
     buttons[i].bind("<Button-3>", lambda event: click(event, i))
     buttons[i].bind("<Button-3>", helper_lambda(i))
root.mainloop()

これで、押された番号の i を参照することができました。

今回の最終コード
import tkinter as tk
from tkinter import messagebox


# クリック関数
def click(event, i):
    messagebox.showinfo("情報", f"{i}をクリックしました")
    return


# ヘルパー関数
def helper_lambda(i):
    return lambda event: click(event, i)


root = tk.Tk()
buttons = []
# 5つのボタンを追加
for i in range(0, 5):
    buttons.append(tk.Button(root, text=f"{i}番目のボタン"))
    buttons[i].pack()
    # bind 処理追加 右クリックに処理を付ける
    # ヘルパー関数を通してクリック関数を呼び出す
    buttons[i].bind("<Button-3>", helper_lambda(i))
root.mainloop()

参考

https://stackoverflow.com/questions/14259072/tkinter-bind-function-with-variable-in-a-loop