Home > python, Tkinter > Tkinter: catturare testo Entry senza bottone

Tkinter: catturare testo Entry senza bottone

27 Novembre 2013

Voglio catturare il testo all’interno di una Entry, mentre lo scrivo.
Ovviamente non voglio fare come su tutte le guide, dove viene utilizzato
un bottone per la cattura.
Voglio fare il bind a e lavorare sul testo in real-time.
Probabilmente esiste un metodo più elegante di questo,
ma il codice seguente fa il suo lavoro.

import Tkinter as tk
import ttk

CHARS = 'abcdefghijklmnopqrstuvwxyz1234567890'
CENTER = tk.N + tk.S + tk.W + tk.E


class ViewTH:
    def __init__(self):
        self.root = tk.Tk()
        self.frame = tk.Frame(self.root)
        self.frame.pack(fill=tk.BOTH)
        self.en_cod = tk.Entry(self.frame)
        self.en_cod.grid(sticky=CENTER, row=0, column=0, padx=2, pady=2)
        btn_quit = tk.Button(self.frame, text='Quit',
                      command=self.root.destroy)
        btn_quit.grid(sticky=CENTER, row=1, column=0, padx=2, pady=2)
        self.en_cod.bind('<KeyPress>', func=self.on_entry)
        self.en_cod.focus_set()

    def on_entry(self, event):
        text = self.en_cod.get()
        char = event.keysym
        index = self.en_cod.index(tk.INSERT)
        if not text:
            string = char
        else:
            if char in CHARS + CHARS.upper():
                string = text + char
            elif char == 'BackSpace':
                if index == 0:
                    string = text
                else:
                    string = text[ :index - 1] + text[index: ]
            elif char == 'Delete':
                string = text[ :index] + text[index + 1: ]
            else:
                 string = text
        print string

    def start(self):
        self.root.mainloop()


if __name__ == '__main__':
    vth = ViewTH()
    vth.start()

In pratica nella callback on_entry, richiamata ad ogni pressione di un tasto all’interno della
Entry, effettuo questi controlli:

…e se il tasto premuto, è il primo della sequenza, lo utilizzo per ottenere il primo
carattere, che altrimenti verrebbe saltato dal metodo get().

...
    def on_entry(self, event):
        text = self.en_cod.get()
        char = event.keysym
        index = self.en_cod.index(tk.INSERT)
        if not text:
            string = char

poi controllo che il carattere premuto (event.symkey), faccia parte di quelli consentiti
(CHARS)

...
        else:
            if char in CHARS + CHARS.upper():
                string = text + char
	    ...
            else:
                 string = text

In più nelle condizioni elif gestisco i casi di ‘BackSpace’ e ‘Delete’,
richiamando l’indice posizionale del cursore all’interno della Entry,
per ottenere il testo corretto in caso di cancellazione caratteri
(soprattutto nel mezzo della stringa).

index = self.en_cod.index(tk.INSERT)

Tutti gli altri tasti non alfanumerici non li considero.
Nel caso comunque premessi ‘Home’ e di seguito ‘BackSpace’, gestirei la stringa all’interno di
questo if/else:

            elif char == 'BackSpace':
                if index == 0:
                    string = text
                else:
                    string = text[ :index - 1] + text[index: ]

…poi è chiaro che con un Button ed una callback che al proprio interno richiami il
metodo get() della Entry ed il testo al suo interno, sarebbe tutto molto più facile,
ma più brutto.

Categorie:python, Tkinter Tag:
I commenti sono chiusi.