Python tkinter: Delete Menu checkbutton
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
|
show 1 more comment
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
@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 atk.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
Useview_menu.bind('<3>', rightClickMenu)
– stovfl
Nov 23 at 14:01
@stovfl that doesn't work though, right clicking underview_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
|
show 1 more comment
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
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
python tkinter
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 atk.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
Useview_menu.bind('<3>', rightClickMenu)
– stovfl
Nov 23 at 14:01
@stovfl that doesn't work though, right clicking underview_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
|
show 1 more comment
@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 atk.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
Useview_menu.bind('<3>', rightClickMenu)
– stovfl
Nov 23 at 14:01
@stovfl that doesn't work though, right clicking underview_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
|
show 1 more comment
1 Answer
1
active
oldest
votes
To the best of my understanding, there's essentially two parts to your question:
Can the menu bar item be assigned for manipulation after?
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.
Thank you for a very insightful answer ! I have figured that0x0004
is CTRL and0x0001
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 justprint(event.state)
during the bind callback to see the value being printed out and get an idea.
– Idlehands
Nov 25 at 5:00
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
To the best of my understanding, there's essentially two parts to your question:
Can the menu bar item be assigned for manipulation after?
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.
Thank you for a very insightful answer ! I have figured that0x0004
is CTRL and0x0001
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 justprint(event.state)
during the bind callback to see the value being printed out and get an idea.
– Idlehands
Nov 25 at 5:00
add a comment |
To the best of my understanding, there's essentially two parts to your question:
Can the menu bar item be assigned for manipulation after?
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.
Thank you for a very insightful answer ! I have figured that0x0004
is CTRL and0x0001
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 justprint(event.state)
during the bind callback to see the value being printed out and get an idea.
– Idlehands
Nov 25 at 5:00
add a comment |
To the best of my understanding, there's essentially two parts to your question:
Can the menu bar item be assigned for manipulation after?
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.
To the best of my understanding, there's essentially two parts to your question:
Can the menu bar item be assigned for manipulation after?
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.
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 that0x0004
is CTRL and0x0001
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 justprint(event.state)
during the bind callback to see the value being printed out and get an idea.
– Idlehands
Nov 25 at 5:00
add a comment |
Thank you for a very insightful answer ! I have figured that0x0004
is CTRL and0x0001
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 justprint(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
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
@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