blog.furas.pl
# prywatne notatki - Python, Linux, Machine Learning, etc.

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()
Książki: python-dla-kazdego-podstawy-programowania python-wprowadzenie python-leksykon-kieszonkowy python-receptury python-programuj-szybko-i-wydajnie python-projekty-do-wykorzystania black-hat-python-jezyk-python-dla-hackerow-i-pentesterow efektywny-python-59-sposobow-na-lepszy-kod tdd-w-praktyce-niezawodny-kod-w-jezyku-python aplikacje-internetowe-z-django-najlepsze-receptury