2011-10-16 11 views
5

¿Cómo suprimir la capacidad del usuario final de editar/agregar/eliminar texto en un widget de texto? (Python v3.2 .. y tkinter)Widget de texto de solo lectura en python3-tkinter; plataforma cruzada

El punto es suprimir solo la capacidad de cambiar/agregar/eliminar texto pero no para castrar otras características. Tal vez un texto NoEdit con ancho sería un nombre mejor.

He intentado .text [ 'estado'] = 'desactivado' y funciona casi Aceptar en Windows (que todavía permite al usuario seleccionar/copiar texto resalta la selección, página arriba/abajo y hacia arriba/botones de abajo funcionan. Lo único roto parece ser el cursor invisible.)

Pero en MacIntosh todo está roto. No se pone de relieve, sin seleccionar/copiar, ... uf

Desde Tkinter no tiene prácticamente ninguna documentación en Python, que haber buscado y encontrado algunos consejos TCL, para derivar una nueva clase y suprimir la inserción y eliminar funciones.

Por lo tanto, he tratado como tal:

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) 

Por desgracia, no funcionó bien. Aparentemente tkinter no usa esas funciones de inserción y eliminación cuando el usuario final ingresa/borra el código. Quizás esos TCL insert/delete sean algo más, y perdí algo en la traducción de TCL y swahili. ¿Qué funciones usa tkinter.Text para el texto de edición del usuario final? Esperemos que no sean internos ...

Entonces, ¿hay alguna manera de modificar el widget de texto para suprimir solo la edición del usuario final? ¿Hay alguna manera de hacerlo sin bucear y anular el código interno de Tkinter, para que las siguientes versiones de Tkinter no lo rompan?

Al mirar la ventana del shell Idle, veo que han logrado suprimir ediciones (excepto la última línea). Entonces hay una manera. ¿Pero qué es y qué tan costoso?

Respuesta

2

El motivo por el que el estado disabled no parece funcionar en la Mac es porque desactiva la vinculación que le da enfoque al widget. Sin foco, el resaltado en una Mac no aparece. Si establece el estado en disabled pero luego asigna un enlace a <ButtonPress-1> para establecer explícitamente el foco en el widget de texto desactivado, puede seleccionar y copiar texto y se mostrará el resaltado.

En cuanto al cursor desapareciendo ... podría decirse que eso es lo que se supone que debe suceder. El cursor le dice al usuario "aquí es donde se insertará el texto". Como no se insertará ningún texto, tener esa pista visual sería confuso para el usuario. Lo que podría hacer, en cambio, si fuera realmente importante, es insertar una imagen pequeña cada vez que haga clic para simular el cursor.

Para responder a su pregunta sobre si el widget utiliza realmente los insert y delete métodos: los métodos en el widget subyacente real son los que utilizan los enlaces por omisión, por lo que ellos imperiosa de una subclase no tiene ningún efecto. Tendrá que volver a hacer todos los enlaces predeterminados para que funcione. Es factible, pero mucho trabajo.

Por desgracia, esta es un área donde la programación en Tcl realmente brilla, porque puede simplemente desactivar las insert y delete comandos del widget. Por supuesto, puedes hacerlo directamente en Tkinter también, ya que en última instancia ejecuta código tcl para hacer todo, pero eso implicaría escribir algún código tcl que no es una solución muy buena desde la perspectiva de un codificador Python.

Creo que la mejor solución es usar el estado deshabilitado, luego agregue los enlaces suficientes para hacer lo que quiera.

Aquí hay un ejemplo simple que funciona al establecer explícitamente el foco en el clic de un botón del mouse. Con este código soy capaz de hacer clic y arrastrar para seleccionar una región, o el doble o triple clic para seleccionar palabras y líneas:

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, tuve la oportunidad de probar en Mac, y el texto.focus_set() vinculado a <1> solucionó el problema, tal como lo dijo. ** ¡Gracias! ** (Quizás esta página se puede limpiar para otros que buscan una solución. Y he visto muchos en la web). Desafortunadamente, como temía, aparentemente era uno de los muchos problemas con el puerto Tkinter para Mac. el color 'verde' no funciona en los botones, el texto en los botones necesita más espacio (este podría estar relacionado con la resolución), etc ... Es fácil solucionarlo, y solo espero que lo peor no aparezca – Momus

-1

@BryanOakley Me tomó un tiempo para probar su sugerencia ya que tengo no Mac Desafortunadamente, la implementación de Mac de Python tiene errores. enfoque que he añadido, es decir, mi función de desactivación que llamo después de crear una ventana y la inserción de texto, ahora llamada por primera vez:

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

y luego

self.txt.focus_set() 

Que es lo que piensa que ha sugirió.

"Funcionó". Es decir: al seleccionar texto (hacer clic y arrastrar o hacer doble clic), resaltar funciona más del tiempo. Python debe tener algunas referencias incorrectas a la memoria o errores similares: a veces el resaltado no funciona al principio, luego comienza a funcionar (en la misma ventana) después de hacer más clic. A veces, cuando se invoca el programa, funciona a la derecha del bate. Algunas veces, seleccionar con la tecla Shift-rightArrow funcionará pero al seleccionar con el mouse no funcionará. Luego comienza a trabajar de nuevo. O funcionará bien en una ventana pero no en otra (ambas de la misma clase), luego comenzará a funcionar en todas las ventanas ... etc ...

Lo bueno es que agregar foco no afectó gravemente Windows (es decir, todo funciona bien como sin foco. Supongo que en este punto, espero que la próxima/próxima versión de Python para Mac solucione esos errores ...

Por cierto, parece que Mac está un poco huérfana para Python. La implementación es mucho más fea que para Windows. Me refiero a que las fuentes son peores, los botones, etc. O podría deberse a diferentes resoluciones de pantalla y puertos de Python que cuentan mal. No estoy seguro

De todos modos. Gracias por su ayuda y sugerencia para usar Focus para Mac.

+0

Necesita para llamar a 'focus_set' en la devolución de llamada para el evento' <1> ', no solo cuando crea el widget. Por su respuesta, parece que solo está enfocando una vez. Repito: para que aparezca el resaltado, el widget debe tener foco. Si lo enfocas, puede perder el foco cada vez que haces clic en otro lugar. Agregar un enlace a '<1>' para establecer el foco se asegurará de que siempre tenga foco cuando intente hacer una selección (ya que cualquier selección siempre comienza con un clic del mouse). –

+0

@BryanOakley No sé a qué te refieres con "devolución de llamada para el evento <1>". Parece que mi suposición estaba equivocada ... Mi próxima conjetura es que sugieres enlazar un solo clic en mi gadget de texto a alguna función de devolución de llamada que llamará ... txt.focus_set() Y tal vez también lo hagas con un doble clic y un triple clic (si tkinter no ha comprobado )> Ahora tengo enlace/devolución de llamada solo para , pero por supuesto podría hacer un enlace especial y una devolución de llamada de una línea con focus_set() solo para esto. Trataré de enviarlo a mi "cliente de Mac" para probar ... Gracias de nuevo. – Momus

+0

mi respuesta original decía "asignar un enlace a para establecer explícitamente el foco en el widget de texto desactivado". Pensé que eso era lo suficientemente claro, pero obviamente no. He agregado un ejemplo para aclarar. Además, no necesita hacer lo mismo con un doble o triple clic, ya que la única forma de hacer un doble o triple clic es hacer primero un solo clic, por lo que esta solución le permitirá duplicar o haga clic tres veces para seleccionar palabras y líneas, y haga clic y arrastre para seleccionar una región. –

2

Perdón por responder una pregunta anterior, pero también estaba buscando una respuesta a esta pregunta y finalmente encontré una solución. La solución que encontré implica anular las asociaciones de teclas cuando el widget de texto tiene foco y es bastante simple. Encontrado here.

Para anular los enlaces de un widget, hay una función de enlace donde pasa una cadena de lo que se va a anular y la nueva función que desea que llame.

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

En algún otro lugar de la clase, tendrá que definir la función para manejar el evento.

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

Al devolver la "ruptura" cadena del controlador de eventos sabe que parar después de su función, en lugar de continuar con la acción predeterminada.

Espero que esto responda a su pregunta. Aclamaciones.

Cuestiones relacionadas