Bind w Tkinter czyli przykłady przypisywania obsługi zdarzeń.
Proste przykłady użycia bind
Na początek okno z kilkoma przyciskami. Zadałem oknu wielkość aby mieć też dostęp bezpośrednio do powierzchni okna.
Do przy przycisków przypisałem funkcje za pomoca command=
#-*- coding: utf-8 -*-
from Tkinter import *
def msg():
print "Wciśnięto (jakiś) Button"
master = Tk()
master.geometry('300x150+100+100')
b_a = Button(master, text="Button A", command=msg)
b_a.grid(row=0, column=0)
b_b = Button(master, text="Button B", command=msg)
b_b.grid(row=0, column=1)
b_c = Button(master, text="Button C", command=msg)
b_c.grid(row=0, column=2)
master.mainloop()
Teraz zamiast command=
do Buttonów przypiszę funkcję reagującą na zdarzenie <Button-1>
czyli kliknięcie lewym przyciskiem myszy. Do tak przypisanej funkcji jest przekazywany jeden argument zawierający informacje o zdarzeniu więc msg
musi ten argument odbierać. Mając informacje o zdarzeniu wypiszę współrzędne w jakim nastąpiło zdarzenie.
Współrzędne przekazywane do Widgeta są przeliczane na jego wewnętrzny układ współrządnych, w którym prawy górny róg widgetu ma współrzędne (0,0). Tak więc klikając w środek każdego Buttona zawsze otrzymujemy (w przybliżeniu) takie same współrzędne
#-*- coding: utf-8 -*-
from Tkinter import *
def msg(event):
print "Wciśnięto (jakiś) Button w pozycji (x,y):", event.x, event.y
master = Tk()
master.geometry('300x150+100+100')
b_a = Button(master, text="Button A")
b_a.grid(row=0, column=0)
b_b = Button(master, text="Button B")
b_b.grid(row=0, column=1)
b_c = Button(master, text="Button C")
b_c.grid(row=0, column=2)
b_a.bind('', msg)
b_b.bind('', msg)
b_c.bind('', msg)
master.mainloop()
Mogę to samo przypisać też do całego okna i zrobię dla niego osobną funkcję aby było widać kto wyświetla współrzędne. Teraz można klikać w puste miejsce okna i też będzie pokazywał się komunikat. Jeśli klikniemy w Button to pojawią się dwa komunikaty - od Buttona i od Mastera - ale oba podają te same współrzędne - przeliczone na układ Buttona.
#-*- coding: utf-8 -*-
from Tkinter import *
def msg_button(event):
print "Wciśnięto (jakiś) Button w pozycji (x,y):", event.x, event.y
def msg_master(event):
print "Wciśnięto master w pozycji (x,y):", event.x, event.y
master = Tk()
master.geometry('300x150+100+100')
b_a = Button(master, text="Button A")
b_a.grid(row=0, column=0)
b_b = Button(master, text="Button B")
b_b.grid(row=0, column=1)
b_c = Button(master, text="Button C")
b_c.grid(row=0, column=2)
b_a.bind('', msg_button)
b_b.bind('', msg_button)
#b_c.bind('', msg_button)
master.bind('', msg_master)
master.mainloop()
Dodająć return "break"
można poinformować system, że zdarzenie zostało obsłużone i nie będzie rozsyłane do pozostałych odbiorców.
Poniżej dodatkowo przykład jak wykorzystać lambda
do przekazania dodatkowego argumentu do funkcji.
Teraz Button A
informuje system, że obsłużył zdarzenie i Master już go nie dostaje, Button B
nie ma przypisanej funkcji do zdarzenia więc tylko Master dostaje zdarzenie, Button C
po staremu nie informuje systemu o obsłużeniu zdarzenia więc funkcja przypisana do master
też jest wywoływana.
#-*- coding: utf-8 -*-
from Tkinter import *
def msg_button(event):
print "Wciśnięto (jakiś) Button w pozycji (x,y):", event.x, event.y
return "break"
def msg_master(event):
print "Wciśnięto master w pozycji (x,y):", event.x, event.y
def msg(event, nazwa):
print "Wciśnięto", nazwa, "w pozycji (x,y):", event.x, event.y
master = Tk()
master.geometry('300x150+100+100')
b_a = Button(master, text="Button A")
b_a.grid(row=0, column=0)
b_b = Button(master, text="Button B")
b_b.grid(row=0, column=1)
b_c = Button(master, text="Button C")
b_c.grid(row=0, column=2)
b_a.bind('', msg_button)
#b_b.bind('', msg_button)
b_c.bind('', lambda e:msg(e,"Button C"))
master.bind('', lambda e:msg(e,"Master"))
master.mainloop()
Zamiast przypisywać do każdego Buttona z osobna można przypisać do całej klasy Button
za pomocą bind_class('nazwa_klasy', ...)
i za jednym zamachem mamy przypisane do istniejących Buttonów i do tych co powstaną w przyszłości.
Tutaj mamy przypisanie <Button-1>
(lewy klawisz myszy) przed powstaniem Buttonów i <Button-3>
(prawy klawisz myszy) po stworzeniu Buttonów
from Tkinter import *
def msg(event, nazwa):
print "Wciśnięto", nazwa, "w pozycji (x,y):", event.x, event.y
master = Tk()
master.geometry('300x150+100+100')
master.bind_class('Button', '', lambda e:msg(e, " na (jakiś) Button"))
b_a = Button(master, text="Button A")
b_a.grid(row=0, column=0)
b_b = Button(master, text="Button B")
b_b.grid(row=0, column=1)
b_c = Button(master, text="Button C")
b_c.grid(row=0, column=2)
master.bind_class('Button', '', lambda e:msg(e, " na (jakiś) Button"))
master.mainloop()
Przypisanie zdarzenia do wszystkich elementów za pomocą bind_all()
Wykorzystanie innych informacji przekazanych przez zdarzenie - dzięki informacji jaki widget został wcisięty można np. zmienić mu napis.
from Tkinter import *
def msg(event):
print 'widget:', event.widget,
' (x,y):', event.x, event.y,
' (x_root,y_root):', event.x_root, event.y_root
if str(event.widget) != '.': # wykluczamy mastera
event.widget['text'] = 'kliknięty'
master = Tk()
master.geometry('300x150+100+100')
b_a = Button(master, text="Button A")
b_a.grid(row=0, column=0)
b_b = Button(master, text="Button B")
b_b.grid(row=0, column=1)
b_c = Button(master, text="Button C")
b_c.grid(row=0, column=2)
master.bind_all('', msg)
master.mainloop()