Come nella maggior parte dei kit software per la realizzazione di interfacce grafiche, anche Tk avvia in automatico un algoritmo interno che gestisce un ciclo continuo di ascolto degli eventi trasmessi dal sistema operativo.

Tra gli eventi più comuni ci sono:

  • la pressione di un pulsante
  • la pressione di un tasto della tastiera
  • il clic o il movimento del mouse
  • il ridimensionamento di una finestra
  • ecc.

La gestione degli eventi implementata in Tk si occupa anche di identificare quale widget è interessato da uno specifico evento.

Come è facile immaginare, ciascuna classe di widgets ha un suo specifico set di eventi che può gestire.

Come associare un comando ad un evento

Il compito del programmatore è quello di associare (binding) un comando (ovvero una procedura/funzione) ad uno specifico evento: per esempio visualizzare una frase in una casella di testo all’atto della pressione di uno specifico pulsante da parte di un utente.

Binding attraverso l’attributo -command

Molti widgets hanno già associato un loro specifico evento: per esempio il click del pulsante sinistro del mouse su un pulsante della nostra interfaccia grafica. In questo caso basta valorizzare l’attributo -command del nostro pulsante con il nome del comando che si vuole far eseguire.

# esempio
proc calculate {} {...}
ttk::button .c.calc -text "Calculate" -command calculate

Binding attraverso una associazione diretta

Per gli eventi che invece non hanno una opzione preconfigurata su un specifico widget, possiamo usare il comando bind per associare ad un widget uno specifico evento e quindi, nel momento in cui il sistema per la gestione degli eventi cattura quell’evento su quel widget viene eseguita una determinata porzione di codice.

# esempio
package require Tk
grid [ttk::label .l -text "Starting..."] 
bind .l <Enter> {.l configure -text "Moved mouse inside"}
bind .l <Leave> {.l configure -text "Moved mouse outside"}
bind .l <ButtonPress-1> {.l configure -text "Clicked left mouse button"}
bind .l <3> {.l configure -text "Clicked third mouse button"}
bind .l <Double-1> {.l configure -text "Double clicked"}
bind .l <B3-Motion> {.l configure -text "third button drag to %x %y"}

In questo esempio vengono associati sei differenti eventi alla etichetta l e, nel momento in cui il sistema per la gestione degli eventi cattura uno di questi eventi, l’attributo -text della etichetta l viene valorizzato con un testo che specifica l’evento occorso.

Vediamo ora in sintesi alcune note per ciascuno di questi sei eventi:

  1. <Enter> accade quando il puntatore del mouse entra all’interno del perimetro del widget a cui è associato.
  2. <Leave> accade quando il puntatore del mouse esce dal perimetro del widget a cui è associato.
  3. <ButtonPress> accade quando si preme su uno qualsiasi dei pulsanti del mouse, ma è anche possibile specificare un pulsante in particolare:
    • Sistemi operativi GNU/Linux e Windows:
      • <ButtonPress-1> pulsante sinistro
      • <ButtonPress-2> pulsante centrale
      • <ButtonPress-3> pulsante destro
    • Sistema operativo macOS:
      • <ButtonPress-1> pulsante sinistro
      • <ButtonPress-2> pulsante destro
      • <ButtonPress-3> pulsante centrale
  4. <3> è l’abbreviazione dell’evento <ButtonPress-3>.
  5. <Double-1> accade quando si fa doppio-click sul pulsante sinistro del mouse.
  6. <B3-Motion> accade quando, tenendo premuto il pulsante tre <B3> del mouse, si muove <Motion> il mouse all’interno del perimetro del widget associato. Questo evento restituisce anche due parametri: le coordinate x ed y del puntatore del mouse.

Nota: il comando bind non fa parte del kit Tk, ma rientra nello spazio dei nomi globali (global namespace) dell’interprete Tcl.

Come associare più comandi ad un evento

Alle volte può presentarsi la necessità di fare qualcosa nel momento in cui accadono in breve tempo più eventi.

Un esempio lo abbiamo già visto più sopra con l’evento <Double-1> che cattura il doppio click del pulsante sinistro del mouse.

Potremmo però voler catturare la pressione in stretta sequenza di due tasti della tastiera, ed allora potremmo usare la sequenza <KeyPress-a><KeyPress-b> (o più concisamente <a><b>).

Per quanto riguarda le lettere dell’alfabeto, l’interprete Tcl fa distinzione tra minuscole e maiuscole. Quindi se volessimo catturare una sequenza di caratteri maiuscoli dovremmo scrivere <KeyPress-A><KeyPress-B> (o più brevemente <A><B>).

Associare un evento alla finestra principale

Possiamo anche associare un certo evento alla finestra principale (toplevel window) in modo tale che se accade quell’evento su uno qualsiasi dei suoi widgets figli, che abbia in quel momento il focus, viene eseguito il comando associato.

Dove trovare la lista degli eventi gestiti da Tk?

Domanda più che legittima.

Il miglior modo per documentarsi sugli eventi è quello di consultare il comando bind sul Manuale ufficiale del linguaggio Tcl/Tk.

Al momento in cui scriviamo è possibile consultare questo link: comando bind (versione 9.1 del linguaggio).

Eventi virtuali

Sino a qui abbiamo discusso degli eventi gestiti direttamente dal sistema operativo (click del mouse, ridimensionamento di una finestra, ecc.). Questi eventi vengono indicati come eventi di basso livello.

Ci sono però anche eventi gestiti dai widgets o direttamente dal kit Tk. Inoltre è anche possibile creare degli eventi ad hoc. Tutte queste tipologie di eventi vengono definite come eventi di alto livello o eventi virtuali.

Associati a singoli widgets

Come abbiamo anticipato, molti widgets sono in grado di generare specifici eventi che prendono il nome di eventi virtuali.

I nomi di questi eventi vengono racchiusi tra coppie di parentesi angolari <<...>>.

Le informazioni di dettagli su ciascuno di questi eventi compare nella documentazione relativa al singolo widget.

Gestiti direttamente da Tk

Ci sono poi degli eventi virtuali non associati direttamente a specifici widget, ma potremmo dire di carattere generale.

Per esempio gli eventi: <Cut>, <Copy> e <Paste> per le classiche operazioni di taglia/copia/incolla.

Oppure il comando <ContextMenu> per attivare la piccola finestra del classico menu contestuale.

Personalizzati

Infine possiamo creare degli eventi virtuali ad hoc da associare alla nostra applicazione.

# sintassi
event generate . "<<MyOwnEvent>>"

Questa possibilità può risultare molto utile per risolvere il problema causato dalla differente gestione di un certo evento dovuta al tipo di sistema operativo in uso.


Nel prossimo articolo vedremo i principali widgets di base.