Search code examples
pythonuser-interfacetkintertreeviewttk

Right Click Menu on Tkinter Treeview widget


I am trying to make a popup menu appear, unique to each row, appear when right clicking on a specific row in a Treeview table with TTK.

I found some code here which does what I'm looking for, but I'm not sure if it's possible for the code to discern between right clicks on one row or another. Below is my full code.

from tkinter import *
from tkinter import ttk
import sys

class Main:
    def __init__(self, root):
        pass

    def treeview_sort_column(self, tv, col, reverse):
        l = [(tv.set(k, col), k) for k in tv.get_children('')]
        try:
            l.sort(key=lambda t: int(t[0]), reverse=reverse)

        except ValueError:
            l.sort(reverse=reverse)

        for index, (val, k) in enumerate(l):
            tv.move(k, '', index)
        tv.heading(col, command=lambda: self.treeview_sort_column(tv, col, not reverse))

    def createWindow(self):
        self.popup = Menu(root, tearoff=0)
        self.popup.add_command(label="Shutdown") # , command=next) etc...
        self.popup.add_command(label="Edit Name")
        self.popup.add_separator()
        self.popup.add_command(label="Exit", command=lambda: self.closeWindow())

        Button(root, text="Exit", command=lambda: self.closeWindow()).pack()

        self.columns = ('Name', 'Age', 'Height')
        self.treeview = ttk.Treeview(root, columns=self.columns, show='headings')
        self.treeview.pack()
        self.treeview.insert('', 'end', values=("Josh", "18", "198"))
        self.treeview.insert('', 'end', values=("LJ", "36", "167"))
        self.treeview.insert('', 'end', values=("Klaudia", "12", "200"))
        self.treeview.insert('', 'end', values=("David", "74", "134"))

        self.treeview.bind("<Button-3>", self.do_popup)

        for col in self.columns:
            self.treeview.heading(col, text=col, command=lambda _col=col: \
                             self.treeview_sort_column(self.treeview, _col, False))

    def closeWindow(self):
        root.destroy()
        sys.exit()

    def do_popup(self, event):
        try:
            self.popup.tk_popup(event.x_root, event.y_root, 0)
        finally:
            self.popup.grab_release()

root = Tk()
X = Main(root)
X.createWindow()

root.mainloop()

Solution

  • What you are looking for is the identify_row() method of the treeview:

    def do_popup(self, event):
        item = self.treeview.identify_row(event.y)
        print('clicked item:', item)
        try:
            self.popup.tk_popup(event.x_root, event.y_root, 0)
        finally:
            self.popup.grab_release()