2010-11-24 86 views
5

Estoy trabajando en Windows XP, con Python 2.6.x y TKinter. Usar un widget de texto en la aplicación, pero falta el menú emergente estándar (cortar, copiar, pegar, eliminar, seleccionar todo). ¿Cómo hacer que aparezca?Menú contextual de Stardand en el widget de texto de Python TKinter cuando se presiona el botón derecho del mouse

+0

Haga clic derecho para un menú contextual, así como lo que aparece en dicho menú si aparece no está ampliamente estandarizado. En las plataformas que lo soportan, hay muchas convenciones para ciertas aplicaciones (como editar texto). La API 'tkinter' es independiente de la plataforma, así que si quieres esta funcionalidad, creo que tendrás que escribir (o encontrar) el código que la implementa o algo parecido a lo que deseas. – martineau

Respuesta

4

Encontré una manera, gracias a this post. Hice algunas modificaciones. En la parte inferior hay un mínimo de main para probarlo.

from Tkinter import * 

def rClicker(e): 
    ''' right click context menu for all Tk Entry and Text widgets 
    ''' 

    try: 
     def rClick_Copy(e, apnd=0): 
      e.widget.event_generate('<Control-c>') 

     def rClick_Cut(e): 
      e.widget.event_generate('<Control-x>') 

     def rClick_Paste(e): 
      e.widget.event_generate('<Control-v>') 

     e.widget.focus() 

     nclst=[ 
       (' Cut', lambda e=e: rClick_Cut(e)), 
       (' Copy', lambda e=e: rClick_Copy(e)), 
       (' Paste', lambda e=e: rClick_Paste(e)), 
       ] 

     rmenu = Menu(None, tearoff=0, takefocus=0) 

     for (txt, cmd) in nclst: 
      rmenu.add_command(label=txt, command=cmd) 

     rmenu.tk_popup(e.x_root+40, e.y_root+10,entry="0") 

    except TclError: 
     print ' - rClick menu, something wrong' 
     pass 

    return "break" 


def rClickbinder(r): 

    try: 
     for b in [ 'Text', 'Entry', 'Listbox', 'Label']: # 
      r.bind_class(b, sequence='<Button-3>', 
         func=rClicker, add='') 
    except TclError: 
     print ' - rClickbinder, something wrong' 
     pass 


if __name__ == '__main__': 
    master = Tk() 
    ent = Entry(master, width=50) 
    ent.pack(anchor="w") 

    #bind context menu to a specific element 
    ent.bind('<Button-3>',rClicker, add='') 
    #or bind it to any Text/Entry/Listbox/Label element 
    #rClickbinder(master) 

    master.mainloop() 
+0

El 'rClickbinder' parece superfluo en este ejemplo anterior. ¿O supongo que deberías llamar a 'rClickbinder (master)' antes de llamar a 'mainloop()'? – scorpiodawg

+0

@scorpiodawg Tienes razón, he editado la respuesta: rClickbinder está ahí porque es un método útil para habilitar el menú contextual en cada elemento de los tipos enumerados. – bluish

1

Pensé que compartiría mi solución, en base a varios fragmentos de código en stackoverflow. Incluye una aplicación mínima para probar:

editar: los enlaces de clase podrían no funcionar. Si ese fuera el caso, use enlaces normales y devuelva "break" en las funciones select_all.

import Tkinter as tk 

if 1: # nice widgets 
    import ttk 
else: 
    ttk = tk 

class EntryPlus(ttk.Entry): 
    def __init__(self, *args, **kwargs): 
     ttk.Entry.__init__(self, *args, **kwargs) 
     _rc_menu_install(self) 
     # overwrite default class binding so we don't need to return "break" 
     self.bind_class("Entry", "<Control-a>", self.event_select_all) 
     self.bind("<Button-3><ButtonRelease-3>", self.show_menu) 

    def event_select_all(self, *args): 
     self.focus_force() 
     self.selection_range(0, tk.END) 

    def show_menu(self, e): 
     self.tk.call("tk_popup", self.menu, e.x_root, e.y_root) 

class TextPlus(tk.Text): 
    def __init__(self, *args, **kwargs): 
     tk.Text.__init__(self, *args, **kwargs) 
     _rc_menu_install(self) 
     # overwrite default class binding so we don't need to return "break" 
     self.bind_class("Text", "<Control-a>", self.event_select_all) 
     self.bind("<Button-3><ButtonRelease-3>", self.show_menu) 

    def event_select_all(self, *args): 
     self.focus_force()   
     self.tag_add("sel","1.0","end") 

    def show_menu(self, e): 
     self.tk.call("tk_popup", self.menu, e.x_root, e.y_root) 


def _rc_menu_install(w): 
    w.menu = tk.Menu(w, tearoff=0) 
    w.menu.add_command(label="Cut") 
    w.menu.add_command(label="Copy") 
    w.menu.add_command(label="Paste") 
    w.menu.add_separator() 
    w.menu.add_command(label="Select all")   

    w.menu.entryconfigure("Cut", command=lambda: w.focus_force() or w.event_generate("<<Cut>>")) 
    w.menu.entryconfigure("Copy", command=lambda: w.focus_force() or w.event_generate("<<Copy>>")) 
    w.menu.entryconfigure("Paste", command=lambda: w.focus_force() or w.event_generate("<<Paste>>")) 
    w.menu.entryconfigure("Select all", command=w.event_select_all)   


if __name__ == "__main__": 

    class SampleApp(tk.Tk): 
     def __init__(self, *args, **kwargs): 
      tk.Tk.__init__(self, *args, **kwargs) 

      self.entry = EntryPlus(self) 
      self.text = TextPlus(self) 

      self.entry.pack() 
      self.text.pack() 

      self.entry.insert(0, "copy paste") 
      self.text.insert(tk.INSERT, "copy paste") 

    app = SampleApp() 
    app.mainloop() 
+0

self.tk.call ("tk_popup", self.menu, e.x_root, e.y_root) se puede transformar en el más fácil self.menu.tk_popup (e.x_root, e.y_root). HTH –

1

Gracias al código de Gonzo y azulada '<Control-c>', botón derecho mi textwidget trabajaron. No tengo 50 reputaciones, pero tuve un problema que tuve que enfrentar, que el botón derecho desencadenará la función independientemente de la ubicación del punto donde se haga clic. averiguado por:

def show_menu(self, e): 
     if e.widget==self.text: 
      self.tk.call("tk_popup", self.menu, e.x_root, e.y_root) 

Ahora solamente emergente del botón derecho se activará cuando se hace clic en el widget de texto.

Cuestiones relacionadas