tkinter 菜单可以发送调用它们的事件吗?

Can tkinter menus send the event in which they were called?

下面是一个弹出菜单命令,我想通过它发送事件数据。我想要事件的 x 和 y 数据,所以我知道要对 ttk 样式树视图(用作 table)的哪个单元格进行操作。目前它调用 "self.toggle_sort_bool" 方法,但我希望它在末尾调用函数 "self.sort_children(event, cur_tree_children)," 但不要这样做,因为我需要在这里弄清楚 passing/receiving 事件。注意:我知道发送是自动的,但接收不是。我忽略了什么吗?

self.heading_popup_menu = tk.Menu(self.treeview, tearoff=0)
self.heading_popup_menu.add_command(label="Reverse Sort", command=self.toggle_sort_bool)

这里是事件旅程的起点,右键单击 ttk 样式的树视图。

self.treeview.bind('<Button-3>', self.pop_up_right_click_detail)

事件的 x_root 和 y_root 被发送到 tk_popup。 Should/can 我要重载它来发送整个事件吗?似乎根中事件的 x 和 y 被发送来告诉弹出窗口在哪里...弹出。

def pop_up_right_click(self, event):
        try:
            self.heading_popup_menu.tk_popup(event.x_root, event.y_root, 0)
        finally:
            self.heading_popup_menu.grab_release()

这是我想从菜单命令中调用的函数。

def sort_children(self, event, cur_tree_children):
    region = self.treeview.identify("region", event.x, event.y)

    if region == "heading":
        #get column number
        col = self.treeview.identify_column(event.x)
        col = int(re.sub('\D', '', col))

        col_names = cur_tree_children.pop(0)
        cur_tree_children.sort(reverse=self.reverse_sort_bool.get(), key=lambda tup: self.sort_disparate_types(tup[col-1])) #toggle reverse somehow
        cur_tree_children.insert(0, col_names)
        self.depopulate_tree()
        self.populate_tree()

是否可以通过菜单发送事件?我很困惑,因为 - 由于缺乏更好的术语 - 事件在通过右键单击弹出菜单调用函数时是多么的脱节。虽然这是一个大 GUI class 的全部内容,但我不想使用 class 实例变量来传达目标单元格数据,因为我认为这是混乱和不好的做法,因此应尽可能避免.

P.S。如果我有足够的声誉,我会在它下面制作标签 BryanOakley 和 post。

一种常用的方法是在显示菜单之前立即修改菜单命令。您可以定义 postcommand ,它定义了一个函数,即 运行 在菜单显示之前,或者您可以在代码中进行修改,使菜单弹出。

既然要将事件传递给函数,最好的解决办法是在弹出菜单之前修改菜单,因为该函数已经有事件对象。

另一种选择是让您的函数设置一些实例变量,而不是修改菜单。然后,您可以在从菜单调用的函数中引用这些实例变量。

既然你说你不想使用实例变量,这里有一个例子显示如何修改菜单:

def show_popup(self, event):
    self.popup.entryconfig("Do Something", command=lambda: self.something(event))
    self.popup.tk_popup(event.x_root, event.y_root)

例子

这是一个完整的工作示例。该代码显示一个 window 和一个带有一些虚拟数据的树视图小部件。如果您在树视图上单击鼠标右键,您将看到一个包含一项的菜单。当您单击该项目时,它将在标签中显示有关单击发生位置的信息。

import tkinter as tk
from tkinter import ttk

class Example(object):
    def __init__(self):
        self.root = tk.Tk()

        self.treeview = ttk.Treeview(self.root, columns=("one", "two", "three"))
        self.label = tk.Label(self.root, width=40)

        self.label.pack(side="bottom", fill="x")
        self.treeview.pack(fill="both", expand=True)

        self.popup = tk.Menu(self.root, tearoff=False)
        self.popup.add_command(label="Do something")

        self.treeview.bind('<Button-3>', self.show_popup)

        for column in self.treeview.cget("columns"):
            self.treeview.column(column, width=50)

        for i in range(10):
            values = ("a%s" % i, "b%s" %i, "c%s" %i)
            self.treeview.insert('', 'end', text="Item %s" % i, values=values)

    def start(self):
        self.root.mainloop()

    def show_popup(self, event):
        self.popup.entryconfig("Do something", command=lambda: self.do_something(event))
        self.popup.tk_popup(event.x_root, event.y_root)

    def do_something(self, event):
        region = self.treeview.identify("region", event.x, event.y)
        col = self.treeview.identify_column(event.x)

        message = "you clicked %s,%s region=%s column=%s" % (event.x, event.y, region, col)
        self.label.configure(text=message)

if __name__ == "__main__":
    Example().start()