tkinter app adding a right click context menu?

Viewed 46725

I have a python-tkinter gui app that I've been trying to find some way to add in some functionality. I was hoping there would be a way to right-click on an item in the app's listbox area and bring up a context menu. Is tkinter able to accomplish this? Would I be better off looking into gtk or some other gui-toolkit?

4 Answers
from tkinter import *
root=Tk()
root.geometry("500x400+200+100")

class Menu_Entry(Entry):
    def __init__(self,perant,*args,**kwargs):
        Entry.__init__(self,perant,*args,**kwargs)
        self.popup_menu=Menu(self,tearoff=0,background='#1c1b1a',fg='white',
                                     activebackground='#534c5c',
                             activeforeground='Yellow')
        self.popup_menu.add_command(label="Cut                     ",command=self.Cut,
                                    accelerator='Ctrl+V')
        self.popup_menu.add_command(label="Copy                    ",command=self.Copy,compound=LEFT,
                                    accelerator='Ctrl+C')
    
        self.popup_menu.add_command(label="Paste                   ",command=self.Paste,accelerator='Ctrl+V')
        self.popup_menu.add_separator()
        self.popup_menu.add_command(label="Select all",command=self.select_all,accelerator="Ctrl+A")
        self.popup_menu.add_command(label="Delete",command=self.delete_only,accelerator=" Delete")
        self.popup_menu.add_command(label="Delete all",command=self.delete_selected,accelerator="Ctrl+D")
        self.bind('<Button-3>',self.popup)
        self.bind("<Control-d>",self.delete_selected_with_e1)
        self.bind('<App>',self.popup)
        self.context_menu = Menu(self, tearoff=0)
        self.context_menu.add_command(label="Cut")
        self.context_menu.add_command(label="Copy")
        self.context_menu.add_command(label="Paste")
         
    def popup(self, event):
      try:
        self.popup_menu.tk_popup(event.x_root, event.y_root, 0)
      finally:
        self.popup_menu.grab_release()

    def Copy(self):
      self.event_generate('<<Copy>>')

    def Paste(self):
      self.event_generate('<<Paste>>')

    def Cut(self):
      self.event_generate('<<Cut>>')

    def delete_selected_with_e1(self,event):
      self.select_range(0, END)
      self.focus()
      self.event_generate("<Delete>")

    def delete_selected(self):
      self.select_range(0, END)
      self.focus()
      self.event_generate("<Delete>")

    def delete_only(self):
      self.event_generate("<BackSpace>")

    def select_all(self):
      self.select_range(0, END)
      self.focus()



ent=Menu_Entry(root)
ent.pack()


root.mainloop()

Important Caveat:

(Assuming the event argument that contains the coordinates is called "event"): Nothing will happen or be visible when you call tk_popup(...) unless you use "event.x_root" and "event.y_root" as arguments. If you do the obvious of using "event.x" and "event.y", it won't work, even though the names of the coordinates are "x" and "y" and there is no mention of "x_root" and "y_root" anywhere within it.

As for the grab_release(..), it's not necessary, anywhere. "tearoff=0" also isn't necessary, setting it to 1 (which is default), simply adds a dotted line entry to the context menu. If you click on it, it detaches the context menu and makes it its own top-level window with window decorators. tearoff=0 will hide this entry. Moreover, it doesn't matter if you set the menu's master to any specific widget or root, or anything at all.

Related