【问题标题】:Tkinter Treeview identify on right click event returns previous right clicked row右键单击事件上的 Tkinter Treeview 识别返回上一个右键单击的行
【发布时间】:2017-12-13 23:36:06
【问题描述】:

我在 tkinter 中有一个使用 python 3 的树视图。 问题是,当我绑定右键单击以获取右键单击行的行 ID 时,我最终获得了前一个事件的实际行 ID。例如,我可以右键单击“项目 1”,这将返回“”,然后我右键单击“项目 2”,它会返回“项目 1”作为 rowID。

def initTreeView(self):
    self.treeView = ttk.Treeview(self.treeSectionFrame)
    self.treeView.heading('#0', text='Projects')

    self.treeView.grid(row=0, column=0, sticky=("N", "S", "E", "W"))            


    self.treeView.bind('<3>', self.rightClickMenu)

def rightClickMenu(self, event):
    def hello():
        print("hello!")
    # create a popup menu
    print(event.x, event.y)
    rowID = self.treeView.identify('item', event.x, event.y)
    if rowID:
        menu = Menu(self.root, tearoff=0)
        menu.add_command(label="Undo", command=hello)
        menu.add_command(label="Redo", command=hello)
        menu.post(event.x_root, event.y_root)

        self.treeView.selection_set(rowID)
        self.treeView.focus_set()
        self.treeView.focus(rowID)
        print(rowID)
    else:
        pass

谢谢,

[编辑]

我发现了一个肮脏的技巧,其中包括使每个项目的标签与其 id 相同,这样您就可以获取实际的 rowID。这也可以使用 value 选项来完成。

self.treeView.insert("", "end", "id-1, tags="id-1", text="Project 1")

...
rowID = self.treeView.identify('item', event.x, event.y)
rowID = self.treeView.item(rowID)["tags"] # gives you actual ID

【问题讨论】:

    标签: python python-3.x tkinter event-handling treeview


    【解决方案1】:

    首先,如果你想打印实际的rowID,那么就直接打印吧:

    ...
    rowID = self.treeView.identify('item', event.x, event.y)
    print(rowID)
    ...
    

    ...但是,当然,这不是您对代码的期望。为了克服这个问题——让我们稍微颠倒一下逻辑:

    def rightClickMenu(self, event):
        def hello():
            print("hello!")
        # create a popup menu
        print(event.x, event.y)
        rowID = self.treeView.identify('item', event.x, event.y)
        if rowID:
            self.treeView.selection_set(rowID)
            self.treeView.focus_set()
            self.treeView.focus(rowID)
            print(rowID)
    
            menu = Menu(self.root, tearoff=0)
            menu.add_command(label="Undo", command=hello)
            menu.add_command(label="Redo", command=hello)
            menu.post(event.x_root, event.y_root)
        else:
            pass
    

    如您所见,现在更改选择不会被 Menu 小部件阻止。

    之所以会这样工作,是因为post 方法会立即显示Menu,而这个事件需要tk 以某种方式处理。因此,我们遇到了主要问题:post 的定位。

    另一个方法示例:

        ...
        menu = Menu(self.root, tearoff=0)
        menu.add_command(label="Undo", command=hello)
        menu.add_command(label="Redo", command=hello)
    
        self.treeView.selection_set(rowID)
        self.treeView.focus_set()
        self.treeView.focus(rowID)
        print(rowID)
        menu.post(event.x_root, event.y_root)
        ...
    

    但在我看来,我认为这里最合乎逻辑的选择是将选择处理提取到另一个函数,并将其用作Menupostcommand 参数。这样一来,您就不会尝试使用一个回调函数同时坐在两把椅子上。

    【讨论】:

    • 谢谢,现在完美运行。反转它是如何工作的?
    • @我是传奇,因为事件队列中有某种重叠(我假设),看起来tkinter返回到主循环,因为用户可以与菜单交互,并且代码执行被阻止而菜单可见。无论如何,我稍微更新了我的答案。
    猜你喜欢
    • 2020-05-20
    • 2022-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多