Python tkinter: Delete Menu checkbutton












1














I want to delete a menu checkbutton when i right click on it.

Its usually done with bind("Mouse3", deletefunction) , BUT i need an actual instance of a checkbutton to bind it with, and the only way to add a checkbutton to a menu i know is a add_checkbutton() method (and i have no access to instance this way). Is there any way i could do this?



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()









share|improve this question
























  • @Idlehands I dont need a wide range of widgets, i need a checkbutton as a menu item, and i want to know if its possible to delete it, when i right click on it. If you create a tk.Checkbutton(root, text="") you cant add it as a menu item.(or at least i dont know how)
    – Bound
    Nov 22 at 21:08












  • Sorry I misunderstood the question, thought it was the regular widget.
    – Idlehands
    Nov 23 at 1:21










  • Use view_menu.bind('<3>', rightClickMenu)
    – stovfl
    Nov 23 at 14:01










  • @stovfl that doesn't work though, right clicking under view_menu didn't execute any command.
    – Idlehands
    Nov 23 at 14:39






  • 1




    You want to right-click on an item in a menu to remove that item from the menu? I think that will be very, very confusing to your users.
    – Bryan Oakley
    Nov 23 at 15:30
















1














I want to delete a menu checkbutton when i right click on it.

Its usually done with bind("Mouse3", deletefunction) , BUT i need an actual instance of a checkbutton to bind it with, and the only way to add a checkbutton to a menu i know is a add_checkbutton() method (and i have no access to instance this way). Is there any way i could do this?



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()









share|improve this question
























  • @Idlehands I dont need a wide range of widgets, i need a checkbutton as a menu item, and i want to know if its possible to delete it, when i right click on it. If you create a tk.Checkbutton(root, text="") you cant add it as a menu item.(or at least i dont know how)
    – Bound
    Nov 22 at 21:08












  • Sorry I misunderstood the question, thought it was the regular widget.
    – Idlehands
    Nov 23 at 1:21










  • Use view_menu.bind('<3>', rightClickMenu)
    – stovfl
    Nov 23 at 14:01










  • @stovfl that doesn't work though, right clicking under view_menu didn't execute any command.
    – Idlehands
    Nov 23 at 14:39






  • 1




    You want to right-click on an item in a menu to remove that item from the menu? I think that will be very, very confusing to your users.
    – Bryan Oakley
    Nov 23 at 15:30














1












1








1







I want to delete a menu checkbutton when i right click on it.

Its usually done with bind("Mouse3", deletefunction) , BUT i need an actual instance of a checkbutton to bind it with, and the only way to add a checkbutton to a menu i know is a add_checkbutton() method (and i have no access to instance this way). Is there any way i could do this?



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()









share|improve this question















I want to delete a menu checkbutton when i right click on it.

Its usually done with bind("Mouse3", deletefunction) , BUT i need an actual instance of a checkbutton to bind it with, and the only way to add a checkbutton to a menu i know is a add_checkbutton() method (and i have no access to instance this way). Is there any way i could do this?



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()






python tkinter






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 22 at 20:59

























asked Nov 22 at 17:52









Bound

84




84












  • @Idlehands I dont need a wide range of widgets, i need a checkbutton as a menu item, and i want to know if its possible to delete it, when i right click on it. If you create a tk.Checkbutton(root, text="") you cant add it as a menu item.(or at least i dont know how)
    – Bound
    Nov 22 at 21:08












  • Sorry I misunderstood the question, thought it was the regular widget.
    – Idlehands
    Nov 23 at 1:21










  • Use view_menu.bind('<3>', rightClickMenu)
    – stovfl
    Nov 23 at 14:01










  • @stovfl that doesn't work though, right clicking under view_menu didn't execute any command.
    – Idlehands
    Nov 23 at 14:39






  • 1




    You want to right-click on an item in a menu to remove that item from the menu? I think that will be very, very confusing to your users.
    – Bryan Oakley
    Nov 23 at 15:30


















  • @Idlehands I dont need a wide range of widgets, i need a checkbutton as a menu item, and i want to know if its possible to delete it, when i right click on it. If you create a tk.Checkbutton(root, text="") you cant add it as a menu item.(or at least i dont know how)
    – Bound
    Nov 22 at 21:08












  • Sorry I misunderstood the question, thought it was the regular widget.
    – Idlehands
    Nov 23 at 1:21










  • Use view_menu.bind('<3>', rightClickMenu)
    – stovfl
    Nov 23 at 14:01










  • @stovfl that doesn't work though, right clicking under view_menu didn't execute any command.
    – Idlehands
    Nov 23 at 14:39






  • 1




    You want to right-click on an item in a menu to remove that item from the menu? I think that will be very, very confusing to your users.
    – Bryan Oakley
    Nov 23 at 15:30
















@Idlehands I dont need a wide range of widgets, i need a checkbutton as a menu item, and i want to know if its possible to delete it, when i right click on it. If you create a tk.Checkbutton(root, text="") you cant add it as a menu item.(or at least i dont know how)
– Bound
Nov 22 at 21:08






@Idlehands I dont need a wide range of widgets, i need a checkbutton as a menu item, and i want to know if its possible to delete it, when i right click on it. If you create a tk.Checkbutton(root, text="") you cant add it as a menu item.(or at least i dont know how)
– Bound
Nov 22 at 21:08














Sorry I misunderstood the question, thought it was the regular widget.
– Idlehands
Nov 23 at 1:21




Sorry I misunderstood the question, thought it was the regular widget.
– Idlehands
Nov 23 at 1:21












Use view_menu.bind('<3>', rightClickMenu)
– stovfl
Nov 23 at 14:01




Use view_menu.bind('<3>', rightClickMenu)
– stovfl
Nov 23 at 14:01












@stovfl that doesn't work though, right clicking under view_menu didn't execute any command.
– Idlehands
Nov 23 at 14:39




@stovfl that doesn't work though, right clicking under view_menu didn't execute any command.
– Idlehands
Nov 23 at 14:39




1




1




You want to right-click on an item in a menu to remove that item from the menu? I think that will be very, very confusing to your users.
– Bryan Oakley
Nov 23 at 15:30




You want to right-click on an item in a menu to remove that item from the menu? I think that will be very, very confusing to your users.
– Bryan Oakley
Nov 23 at 15:30












1 Answer
1






active

oldest

votes


















1














To the best of my understanding, there's essentially two parts to your question:




  1. Can the menu bar item be assigned for manipulation after?


  2. Can the referenced item be then bound to an event?





The first answer is, sort of. While you can't exactly assign the object, you can reference it by index like this:



view_menu.delete(0)


Since you added the checkbutton first, it'll have an index of 0. You can either keep track of the indices, or refer to the item by its label. See this related answer from Bryan Oakley. e.g.:



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


The .index() method will locate the index by the menu entry's label, which can be handy unless you have the same label more than once...





The second answer, as far as I'm aware, there doesn't seem to be any effective binding for typical events like mouse clicks. However after some search I did come across a rather hidden <<MenuSelect>> binding that at least triggers an event. That by itself is not useful to your quest, but you can combine the event state with the checkbutton's command argument as well as a boolean flag to trigger an event on click:



# 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)


Note: You will actually have to hold right click and then left click on the checkbutton to delete it. Obviously the drawback is you have now triggered the on/off value, and you might need to have some additional handling on those.



If right + left click is too awkward, Ctrl/Shift is another mod state you might consider.



Another side note: I'm a proponent of OOP when it comes to tkinter, it makes accessible variables and flags much easier without needing to worry the global and nonlocal namespaces. Here since delete_checkbutton is set in the global namespace I avoied using the global keyword and accessed it via the tk.BooleanVar() object. However if you were to use a python boolean (e.g. flag = True) then it won't be as effective unless you indicate global flag in both functions. If however you took an OOP approach you can reference the flags directly via self.flag without ambiguity.





Finally, here are the comprehensive changes implemented into your code for sampling:



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()


All that said, I am of the opinion that this is not a very smooth User Experience and is somewhat confusing. Just the permanent deletion of the menu item alone is questionable at best, combined with the method you are trying to call upon the deletion feels even more contrived. I'd suggest revisiting your UX flow to consider how to streamline this.






share|improve this answer























  • Thank you for a very insightful answer ! I have figured that 0x0004 is CTRL and 0x0001 is shift, but how can I check which hex value represents which key?
    – Bound
    Nov 24 at 13:08










  • I have linked a list of the hex values in my answer under "event state", but here it is again. If you ever forget though, it's easy to just print(event.state) during the bind callback to see the value being printed out and get an idea.
    – Idlehands
    Nov 25 at 5:00











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53436119%2fpython-tkinter-delete-menu-checkbutton%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









1














To the best of my understanding, there's essentially two parts to your question:




  1. Can the menu bar item be assigned for manipulation after?


  2. Can the referenced item be then bound to an event?





The first answer is, sort of. While you can't exactly assign the object, you can reference it by index like this:



view_menu.delete(0)


Since you added the checkbutton first, it'll have an index of 0. You can either keep track of the indices, or refer to the item by its label. See this related answer from Bryan Oakley. e.g.:



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


The .index() method will locate the index by the menu entry's label, which can be handy unless you have the same label more than once...





The second answer, as far as I'm aware, there doesn't seem to be any effective binding for typical events like mouse clicks. However after some search I did come across a rather hidden <<MenuSelect>> binding that at least triggers an event. That by itself is not useful to your quest, but you can combine the event state with the checkbutton's command argument as well as a boolean flag to trigger an event on click:



# 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)


Note: You will actually have to hold right click and then left click on the checkbutton to delete it. Obviously the drawback is you have now triggered the on/off value, and you might need to have some additional handling on those.



If right + left click is too awkward, Ctrl/Shift is another mod state you might consider.



Another side note: I'm a proponent of OOP when it comes to tkinter, it makes accessible variables and flags much easier without needing to worry the global and nonlocal namespaces. Here since delete_checkbutton is set in the global namespace I avoied using the global keyword and accessed it via the tk.BooleanVar() object. However if you were to use a python boolean (e.g. flag = True) then it won't be as effective unless you indicate global flag in both functions. If however you took an OOP approach you can reference the flags directly via self.flag without ambiguity.





Finally, here are the comprehensive changes implemented into your code for sampling:



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()


All that said, I am of the opinion that this is not a very smooth User Experience and is somewhat confusing. Just the permanent deletion of the menu item alone is questionable at best, combined with the method you are trying to call upon the deletion feels even more contrived. I'd suggest revisiting your UX flow to consider how to streamline this.






share|improve this answer























  • Thank you for a very insightful answer ! I have figured that 0x0004 is CTRL and 0x0001 is shift, but how can I check which hex value represents which key?
    – Bound
    Nov 24 at 13:08










  • I have linked a list of the hex values in my answer under "event state", but here it is again. If you ever forget though, it's easy to just print(event.state) during the bind callback to see the value being printed out and get an idea.
    – Idlehands
    Nov 25 at 5:00
















1














To the best of my understanding, there's essentially two parts to your question:




  1. Can the menu bar item be assigned for manipulation after?


  2. Can the referenced item be then bound to an event?





The first answer is, sort of. While you can't exactly assign the object, you can reference it by index like this:



view_menu.delete(0)


Since you added the checkbutton first, it'll have an index of 0. You can either keep track of the indices, or refer to the item by its label. See this related answer from Bryan Oakley. e.g.:



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


The .index() method will locate the index by the menu entry's label, which can be handy unless you have the same label more than once...





The second answer, as far as I'm aware, there doesn't seem to be any effective binding for typical events like mouse clicks. However after some search I did come across a rather hidden <<MenuSelect>> binding that at least triggers an event. That by itself is not useful to your quest, but you can combine the event state with the checkbutton's command argument as well as a boolean flag to trigger an event on click:



# 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)


Note: You will actually have to hold right click and then left click on the checkbutton to delete it. Obviously the drawback is you have now triggered the on/off value, and you might need to have some additional handling on those.



If right + left click is too awkward, Ctrl/Shift is another mod state you might consider.



Another side note: I'm a proponent of OOP when it comes to tkinter, it makes accessible variables and flags much easier without needing to worry the global and nonlocal namespaces. Here since delete_checkbutton is set in the global namespace I avoied using the global keyword and accessed it via the tk.BooleanVar() object. However if you were to use a python boolean (e.g. flag = True) then it won't be as effective unless you indicate global flag in both functions. If however you took an OOP approach you can reference the flags directly via self.flag without ambiguity.





Finally, here are the comprehensive changes implemented into your code for sampling:



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()


All that said, I am of the opinion that this is not a very smooth User Experience and is somewhat confusing. Just the permanent deletion of the menu item alone is questionable at best, combined with the method you are trying to call upon the deletion feels even more contrived. I'd suggest revisiting your UX flow to consider how to streamline this.






share|improve this answer























  • Thank you for a very insightful answer ! I have figured that 0x0004 is CTRL and 0x0001 is shift, but how can I check which hex value represents which key?
    – Bound
    Nov 24 at 13:08










  • I have linked a list of the hex values in my answer under "event state", but here it is again. If you ever forget though, it's easy to just print(event.state) during the bind callback to see the value being printed out and get an idea.
    – Idlehands
    Nov 25 at 5:00














1












1








1






To the best of my understanding, there's essentially two parts to your question:




  1. Can the menu bar item be assigned for manipulation after?


  2. Can the referenced item be then bound to an event?





The first answer is, sort of. While you can't exactly assign the object, you can reference it by index like this:



view_menu.delete(0)


Since you added the checkbutton first, it'll have an index of 0. You can either keep track of the indices, or refer to the item by its label. See this related answer from Bryan Oakley. e.g.:



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


The .index() method will locate the index by the menu entry's label, which can be handy unless you have the same label more than once...





The second answer, as far as I'm aware, there doesn't seem to be any effective binding for typical events like mouse clicks. However after some search I did come across a rather hidden <<MenuSelect>> binding that at least triggers an event. That by itself is not useful to your quest, but you can combine the event state with the checkbutton's command argument as well as a boolean flag to trigger an event on click:



# 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)


Note: You will actually have to hold right click and then left click on the checkbutton to delete it. Obviously the drawback is you have now triggered the on/off value, and you might need to have some additional handling on those.



If right + left click is too awkward, Ctrl/Shift is another mod state you might consider.



Another side note: I'm a proponent of OOP when it comes to tkinter, it makes accessible variables and flags much easier without needing to worry the global and nonlocal namespaces. Here since delete_checkbutton is set in the global namespace I avoied using the global keyword and accessed it via the tk.BooleanVar() object. However if you were to use a python boolean (e.g. flag = True) then it won't be as effective unless you indicate global flag in both functions. If however you took an OOP approach you can reference the flags directly via self.flag without ambiguity.





Finally, here are the comprehensive changes implemented into your code for sampling:



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()


All that said, I am of the opinion that this is not a very smooth User Experience and is somewhat confusing. Just the permanent deletion of the menu item alone is questionable at best, combined with the method you are trying to call upon the deletion feels even more contrived. I'd suggest revisiting your UX flow to consider how to streamline this.






share|improve this answer














To the best of my understanding, there's essentially two parts to your question:




  1. Can the menu bar item be assigned for manipulation after?


  2. Can the referenced item be then bound to an event?





The first answer is, sort of. While you can't exactly assign the object, you can reference it by index like this:



view_menu.delete(0)


Since you added the checkbutton first, it'll have an index of 0. You can either keep track of the indices, or refer to the item by its label. See this related answer from Bryan Oakley. e.g.:



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


The .index() method will locate the index by the menu entry's label, which can be handy unless you have the same label more than once...





The second answer, as far as I'm aware, there doesn't seem to be any effective binding for typical events like mouse clicks. However after some search I did come across a rather hidden <<MenuSelect>> binding that at least triggers an event. That by itself is not useful to your quest, but you can combine the event state with the checkbutton's command argument as well as a boolean flag to trigger an event on click:



# 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)


Note: You will actually have to hold right click and then left click on the checkbutton to delete it. Obviously the drawback is you have now triggered the on/off value, and you might need to have some additional handling on those.



If right + left click is too awkward, Ctrl/Shift is another mod state you might consider.



Another side note: I'm a proponent of OOP when it comes to tkinter, it makes accessible variables and flags much easier without needing to worry the global and nonlocal namespaces. Here since delete_checkbutton is set in the global namespace I avoied using the global keyword and accessed it via the tk.BooleanVar() object. However if you were to use a python boolean (e.g. flag = True) then it won't be as effective unless you indicate global flag in both functions. If however you took an OOP approach you can reference the flags directly via self.flag without ambiguity.





Finally, here are the comprehensive changes implemented into your code for sampling:



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()


All that said, I am of the opinion that this is not a very smooth User Experience and is somewhat confusing. Just the permanent deletion of the menu item alone is questionable at best, combined with the method you are trying to call upon the deletion feels even more contrived. I'd suggest revisiting your UX flow to consider how to streamline this.







share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 23 at 15:53

























answered Nov 23 at 15:47









Idlehands

3,9721417




3,9721417












  • Thank you for a very insightful answer ! I have figured that 0x0004 is CTRL and 0x0001 is shift, but how can I check which hex value represents which key?
    – Bound
    Nov 24 at 13:08










  • I have linked a list of the hex values in my answer under "event state", but here it is again. If you ever forget though, it's easy to just print(event.state) during the bind callback to see the value being printed out and get an idea.
    – Idlehands
    Nov 25 at 5:00


















  • Thank you for a very insightful answer ! I have figured that 0x0004 is CTRL and 0x0001 is shift, but how can I check which hex value represents which key?
    – Bound
    Nov 24 at 13:08










  • I have linked a list of the hex values in my answer under "event state", but here it is again. If you ever forget though, it's easy to just print(event.state) during the bind callback to see the value being printed out and get an idea.
    – Idlehands
    Nov 25 at 5:00
















Thank you for a very insightful answer ! I have figured that 0x0004 is CTRL and 0x0001 is shift, but how can I check which hex value represents which key?
– Bound
Nov 24 at 13:08




Thank you for a very insightful answer ! I have figured that 0x0004 is CTRL and 0x0001 is shift, but how can I check which hex value represents which key?
– Bound
Nov 24 at 13:08












I have linked a list of the hex values in my answer under "event state", but here it is again. If you ever forget though, it's easy to just print(event.state) during the bind callback to see the value being printed out and get an idea.
– Idlehands
Nov 25 at 5:00




I have linked a list of the hex values in my answer under "event state", but here it is again. If you ever forget though, it's easy to just print(event.state) during the bind callback to see the value being printed out and get an idea.
– Idlehands
Nov 25 at 5:00


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53436119%2fpython-tkinter-delete-menu-checkbutton%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

What visual should I use to simply compare current year value vs last year in Power BI desktop

Alexandru Averescu

Trompette piccolo