首页 > 解决方案 > Python tkinter:删除菜单检查按钮

问题描述

当我右键单击它时,我想删除一个菜单检查按钮。
它通常用 来完成bind("Mouse3", deletefunction),但我需要一个检查按钮的实际实例来绑定它,并且将检查按钮添加到我知道的菜单的唯一方法是一种add_checkbutton()方法(我无法通过这种方式访问​​实例)。我有什么办法可以做到这一点?

import tkinter as tk

root = tk.Tk()
menubar = tk.Menu(root)
view_menu = tk.Menu(menubar, tearoff=0)
view_menu.add_checkbutton(label="Right click on me to delete", onvalue=1, offvalue=False)
# I want to do something like this:
# c = Checkbutton(label="Right click on me to delete")
# c.bind("Mouse3", my_delete_function())
# view_menu.add(c)
menubar.add_cascade(label='View', menu=view_menu)
root.config(menu=menubar)
root.mainloop()

标签: pythontkinter

解决方案


据我了解,您的问题基本上有两个部分:

  1. 之后可以分配菜单栏项以进行操作吗?

  2. 然后可以将引用的项目绑定到事件吗?


第一个答案是,有点。虽然您无法准确分配对象,但您可以通过索引引用它,如下所示:

view_menu.delete(0)

由于您添加了checkbutton第一个,它的索引为 0。您可以跟踪索引,也可以通过它的label. 请参阅 Bryan Oakley 的相关回答。例如:

view_menu.delete(view_menu.index("Right click on me to delete"))

.index()方法将index通过菜单条目找到label,这很方便,除非您多次使用相同的标签...


第二个答案,据我所知,对于鼠标点击等典型事件似乎没有任何有效的绑定。然而,经过一番搜索,我确实遇到了一个相当隐藏的<<MenuSelect>>绑定,它至少会触发一个事件。 这本身对您的 quest 没有用,但您可以将事件状态checkbuttoncommand参数以及布尔标志结合起来以触发点击事件:

# Add a BooleanVar for flagging:
delete_checkbutton = tk.BooleanVar()

# Add a binding to your view_menu 
view_menu.bind('<<MenuSelect>>', event_state)

# Define the callback function:
def event_state(e):
    if bool(e.state & 0x0400):  # watch for the Mouse Right click state
        # you might opt to use 0x0004 or 0x0001 instead
        # i.e. Ctrl+click or Shift+Click
        delete_checkbutton.set(True)
    else:  # If the state is not right click, reset the flag
        delete_checkbutton.set(False)

# Define a self_delete command for the checkbutton
def self_delete():
    if delete_checkbutton.get():
        view_menu.delete(view_menu.index("Right click on me to delete"))

# Add the command to your checkbutton
view_menu.add_checkbutton(label="Right click on me to delete", onvalue=lambda:print('hey'), offvalue=False, command=self_delete)

注意:您实际上必须按住右键单击然后左键单击以将checkbutton其删除。显然,缺点是您现在已经触发了开/关值,您可能需要对它们进行一些额外的处理。

如果右键 + 左键单击太尴尬,Ctrl/Shift 是您可能会考虑的另一种模式状态。

另一个注意事项:当涉及到 时,我是 OOP 的支持者tkinter,它使可访问的变量和标志变得更加容易,而无需担心globalnonlocal命名空间。这里因为delete_checkbutton是在global命名空间中设置的,我避免使用global关键字并通过tk.BooleanVar()对象访问它。但是,如果您要使用 python 布尔值(例如),那么除非您在两个函数中都指定,flag = True否则它不会那么有效。global flag但是,如果您采用 OOP 方法,则可以直接引用标志,self.flag而不会产生歧义。


最后,以下是在您的采样代码中实施的全面更改:

import tkinter as tk

def event_state(e):
    if bool(e.state & 0x0400):
        # you might opt to use 0x0004 or 0x0001 instead
        # i.e. Ctrl+click or Shift+Click
        delete_checkbutton.set(True)
    else:
        delete_checkbutton.set(False)

def self_delete():
    if delete_checkbutton.get():
        view_menu.delete(view_menu.index("Right click on me to delete"))

root = tk.Tk()
menubar = tk.Menu(root)
delete_checkbutton = tk.BooleanVar()
view_menu = tk.Menu(menubar, tearoff=0)
view_menu.add_command(label='dude', command=lambda: print('dude'))
view_menu.add_checkbutton(label="Right click on me to delete", onvalue=lambda:print('hey'), offvalue=False, command=self_delete)
menubar.add_cascade(label='View', menu=view_menu)
root.config(menu=menubar)
view_menu.bind('<<MenuSelect>>', event_state)
root.mainloop()

综上所述,我认为这不是一个非常流畅的用户体验,而且有点令人困惑。仅永久删除菜单项充其量是有问题的,再加上您尝试调用删除的方法,感觉更加做作。我建议重新审视您的 UX 流程以考虑如何简化此流程。


推荐阅读