2011-10-16 18 views
5

Come sopprimere la capacità dell'utente finale di modificare/aggiungere/eliminare il testo in un widget Testo? (Python v3.2 .. e tkinter)Read Only Widget di testo in python3-tkinter; multipiattaforma

Il punto è sopprimere solo la possibilità di modificare/aggiungere/eliminare il testo ma non per castrare altre funzioni. Forse un NoEdit Text widged sarebbe un nome migliore.

Ho provato .text [ 'stato'] = 'disattivato' e funziona quasi OK in Windows (permette comunque all'utente di selezionare/copiare il testo evidenzia la selezione, pagina su/giù e su/down funzionano. L'unica cosa rotta sembra essere il cursore reso invisibile.)

Ma su MacIntosh è tutto rotto. Non mette in evidenza, senza selezionare/copiare, ... uffa

Dal Tkinter non ha praticamente alcuna documentazione in Python, ho cercato e trovato alcuni TCL consiglio, per derivare una nuova classe e sopprimere l'inserto e cancellare funzioni.

Così, ho provato come così:

class roText(tk.Text): 
    def insert(self,*args,**kwargs): 
     print(" Hey - Im inside roText.insert") 
     pass 
    def delete(self,*args,**twargs): 
     pass  
    def pInsert(self,*args,**twargs): 
     super().insert(*args,**twargs) 

Purtroppo non ha funzionato bene. Apparentemente tkinter non usa quelle funzioni di inserimento ed eliminazione quando l'utente finale inserisce/cancella il codice. Forse questi inserimenti/cancri TCL sono qualcos'altro, e ho perso qualcosa nella traduzione da TCL e Swahili. Quali funzioni utilizza tkinter.Text per il testo di modifica dell'utente finale? Speriamo che non siano interni ...

Quindi, c'è un modo per modificare il widget Testo per sopprimere solo la modifica dell'utente finale? C'è un modo per farlo senza immergersi all'interno e sovrascrivere il codice interno di Tkinter, quindi le cose non verranno interrotte dalle prossime versioni di Tkinter?

Guardando la finestra della shell inattiva, vedo che sono riusciti a eliminare le modifiche (tranne che per l'ultima riga). Quindi c'è un modo. Ma cos'è e quanto costa?

risposta

2

Il motivo per cui lo stato disabled non sembra funzionare sul Mac è perché disattiva l'associazione che concentra il focus sul widget. Senza messa a fuoco, l'evidenziazione su un Mac non viene visualizzata. Se si imposta lo stato su disabled ma si assegna un binding a <ButtonPress-1> per impostare esplicitamente lo stato attivo sul widget di testo disabilitato, è possibile selezionare e copiare il testo e l'evidenziazione verrà visualizzato.

Per quanto riguarda il cursore che scompare ... probabilmente, questo è ciò che dovrebbe succedere. Il cursore dice all'utente "è qui che il testo verrà inserito". Dal momento che nessun testo verrà inserito, avere quell'indizio visivo potrebbe confondere l'utente. Quello che potresti fare invece, se fosse davvero importante, è inserire una piccola immagine ovunque clicchi per simulare il cursore.

per rispondere alla tua domanda se il widget in realtà usa i insert e delete metodi: i metodi sul widget di reale sottostante sono ciò che usano le associazioni di default, in modo da l'override in una sottoclasse non ha effetto. Dovresti ripristinare tutti i binding predefiniti per farlo funzionare. È fattibile, ma molto lavoro.

Purtroppo, questo è un settore in cui la programmazione in Tcl brilla davvero, perché si può semplicemente disattivare le insert e delete comandi del widget. Naturalmente, è possibile farlo direttamente in Tkinter anche perché alla fine esegue il codice tcl per fare tutto, ma ciò implicherebbe la scrittura di un codice tcl che non è una soluzione molto buona dal punto di vista di un coder Python.

Penso che la soluzione migliore sia utilizzare lo stato disabilitato, quindi aggiungere abbastanza associazioni per fare ciò che si desidera.

Ecco un semplice esempio che funziona impostando esplicitamente lo stato attivo su un clic del mouse. Con questo codice sono in grado di fare clic e strisciare per selezionare una regione, o doppio-o triplo-clic per selezionare le parole e le linee:

import Tkinter as tk 

class SampleApp(tk.Tk): 
    def __init__(self, *args, **kwargs): 
     tk.Tk.__init__(self, *args, **kwargs) 
     self.text = tk.Text(width=40, height=20) 
     self.text.bind("<1>", self.set_focus) 
     self.text.insert("end", "\n".join(dir(tk.Tk))) 
     self.text.configure(state="disabled") 
     self.text.pack(fill="both", expand=True) 

    def set_focus(self, event): 
     '''Explicitly set focus, so user can select and copy text''' 
     self.text.focus_set() 

if __name__ == "__main__": 
    app = SampleApp() 
    app.mainloop() 
+0

OK, ho avuto la possibilità di eseguire il test su Mac e il parametro text.focus_set() associato a <1> ha risolto il problema, proprio come avevate detto. ** Grazie !!! ** (Forse questa pagina può essere ripulita per gli altri in cerca di una soluzione. E ne ho visti molti sul web). Sfortunatamente come temevo era apparentemente uno dei molti problemi con Tkinter port to Mac. il colore "verde" non funziona sui pulsanti, il testo sui pulsanti richiede più spazio (questo potrebbe essere correlato alla risoluzione), ecc. Questi sono facili da aggirare, e spero solo che peggio non venga visualizzato – Momus

-1

@BryanOakley Mi c'è voluto un po 'per testare il vostro suggerimento dal momento che ho no Mac. Purtroppo l'implementazione Mac di Python è bacata. attenzione Ho aggiunto, vale a dire la mia funzione di disabilitazione che io chiamo dopo la creazione di una finestra e l'inserimento di testo, ora chiamate prima:

self.txt['state'] = 'disabled' 

e poi

self.txt.focus_set() 

Che è quello che pensi di aver suggerito.

Questo "tipo di" ha funzionato. Cioè: quando si seleziona il testo (fare clic e trascinare o doppio clic) evidenziatura funziona più del tempo. Python deve avere alcuni riferimenti di memoria cattivi o simili bug: A volte l'evidenziazione non funziona, quindi inizia a funzionare (nella stessa finestra) dopo un altro clic. A volte, quando il programma viene richiamato, funziona correttamente. A volte la selezione con il tasto Maiusc-destraArrow funzionerà ma selezionando con il mouse no. Quindi riprende a lavorare. O funzionerà bene in una finestra ma non in un'altra (entrambe della stessa classe), quindi inizia a lavorare in tutte le finestre ... ecc ...

La cosa buona è che l'aggiunta di messa a fuoco non ha influenzato male Windows Immagino che a questo punto spero solo che la prossima versione di Python per Mac risolverà questi bug ..

BTW, sembra che Mac sia un po 'orfano per Python. L'implementazione è molto più brutta di Windows: voglio dire che i font sembrano peggiori, i pulsanti, ecc. Oppure potrebbe essere dovuto a diverse risoluzioni dello schermo e porte Python che non tengono conto di quelle. Non sicuro

In ogni caso. Grazie per il tuo aiuto e il tuo suggerimento di utilizzare lo stato attivo per Mac.

+0

per chiamare 'focus_set' nel callback per l'evento' <1> ', non solo quando si crea il widget. Dalla tua risposta sembra che tu stia mettendo a fuoco solo una volta. Ripeto: per l'evidenziazione da mostrare, il widget deve essere attivo. Se lo si concentra, può perdere la concentrazione ogni volta che si fa clic in qualsiasi altro punto. L'aggiunta di un'associazione a '<1>' per impostare lo stato attivo assicurerà che abbia sempre lo stato attivo quando si tenta di eseguire una selezione (poiché ogni selezione inizia sempre con un clic del mouse). –

+0

@BryanOakley Non so cosa intendi con "callback per l'evento <1>". Sembra che la mia ipotesi fosse sbagliata ... La mia prossima ipotesi è che tu suggerisca di associare un singolo clic nel mio gadget di testo ad una funzione di callback che chiamerà ... txt.focus_set() E forse fallo anche per un doppio clic , e un triplo clic (se tkinter ha non ha ancora controllato)> In questo momento ho binding/callback solo per ma ovviamente potrei creare un binding speciale e una callback di una riga con focus_set() solo per questo. Proverò a inviarlo al mio "client Mac" per testare ... Grazie ancora. – Momus

+0

la mia risposta originale diceva "assegna un binding a per impostare esplicitamente lo stato attivo sul widget di testo disabilitato". Pensavo che fosse abbastanza chiaro, ma ovviamente no. Ho aggiunto un esempio per chiarire. Inoltre, non è necessario fare lo stesso per un doppio o triplo clic, poiché l'unico modo per fare un doppio o triplo clic è di fare prima un clic singolo, quindi questa soluzione ti permetterà di raddoppiare oppure fare triplo clic per selezionare parole e linee, nonché fare clic e trascinare per selezionare una regione. –

2

Ci scusiamo per aver urtato una vecchia domanda, ma stavo cercando una risposta a questa domanda e infine ho trovato una soluzione. La soluzione che ho trovato riguarda la sovrascrittura delle associazioni di tasti quando il widget di testo è focalizzato ed è piuttosto semplice. Trovato here.

Per sovrascrivere i collegamenti di un widget, esiste una funzione di associazione in cui si passa una stringa di ciò che deve essere sovrascritto e la nuova funzione che si desidera chiamare.

self.txtBox.bind("<Key>", self.empty) 

In qualche altro punto della classe è necessario definire la funzione per gestire l'evento.

def empty(self, event): 
     return "break" 

Restituendo la "rottura" stringa il gestore di eventi sa di fermarsi dopo la funzione, invece di continuare con l'azione predefinita.

Spero che questo risponda alla tua domanda. Saluti.