Stardand context menu in Python TKinter text widget when mouse right button is pressed Stardand context menu in Python TKinter text widget when mouse right button is pressed tkinter tkinter

Stardand context menu in Python TKinter text widget when mouse right button is pressed


I found a way, thanks to this post. I made some modifications. At the bottom part there's a minimal main to try it.

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'        passif __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()


Thought I would share my solution, based on several code snippets on stackoverflow. It includes a minimum application to test:

edit: class bindings might not work. Should that be the case use normal bindings and return "break" in the select_all functions.

import Tkinter as tkif 1:  # nice widgets    import ttkelse:    ttk = tkclass 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()


Thanks to Gonzo's code and bluish '<Control-c>', my textwidget right button worked.I don't have 50 reputations but I had a problem which I faced that the right button will trigger the function regardless of the location of the point clicked.figured that out by:

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

Now only the right button's popup will be triggered when you click on text widget.