Code example is from this answer.
When click a Button with a command function (and this command function itself will call another menu command function), like the code example, what would happen? When clicking Refresh menu
why has lambda command
show()
not been activated?
For clarity, I made some changes about the original code as below:
- comment out
Button().invoke
- add some
print()
information - and change/add some
counting variables
# Using lambda keyword and refresh function to create a dynamic menu.
# Set python script name as `tk_dynamic.py`
import tkinter as tk
choice_count = 0
refresh_count = 0
invoke_count = 1
def show(label, count):
""" Show your choice """
global label_choice, choice_count
choice_count += 1
new_label = 'Choice is: ' + label
menubar.entryconfigure(label_choice, label=new_label) # change menu text
label_choice = new_label # update menu label to find it next time
print("\nUpdate root menubar(id {})'s label as `{}`\n\
when adding command #{} to cascade menu(id {}) at refresh count {} in `show()`"\
.format(id(menubar), label_choice, count, id(menu), refresh_count))
choice.set(label)
print("Reset `variable choice` {} {} as {} in show() when adding command #{}\n"\
.format(choice_count, 'times' if choice_count > 1 else 'time', label, count))
def refresh():
""" Refresh menu contents """
global label_choice, label_cascade, refresh_count, choice_count
refresh_count += 1
if label_cascade[0] == 'one':
label_cascade = ['four', 'five', 'six', 'seven']
else:
label_cascade = ['one', 'two', 'three']
choice.set('')
choice_count = 0 # reset choice changing count
menu.delete(0, 'end') # delete previous contents of the menu
menubar.entryconfigure(label_choice, label=const_str) # change menu text
label_choice = const_str # update menu label to find it next time
print('\nUpdate root menubar(id {}) and set label as `{}` {} {} in `refresh()`'\
.format(id(menubar), label_choice, refresh_count, 'times' if refresh_count > 1 else 'time'))
command_count = 1
for l in label_cascade:
menu.add_command(label=l, command=lambda label=l, count=command_count: show(label, count))
print("Add command #{} to cascade menu(id {}) by calling show() at refresh count {}"\
.format(command_count, id(menu), refresh_count))
print("Choice change count is {} when adding command #{} at refresh count {}"\
.format(choice_count, command_count, refresh_count))
command_count += 1
root = tk.Tk()
# Set some variables
choice = tk.StringVar()
const_str = 'Choice'
label_choice = const_str
label_cascade = ['dummy']
# Create some widgets
menubar = tk.Menu(root)
root.configure(menu=menubar)
# menu = tk.Menu(menubar, tearoff=False)
menu = tk.Menu()
print('Before adding cascade menu(id {}) to root menubar(id {})'.format(id(menu), id(menubar)))
menubar.add_cascade(label=label_choice, menu=menu)
b = tk.Button(root, text='Refresh menu', command=refresh)
b.pack()
# b.invoke()
# print("Invoke {} {} button command"\
# .format(invoke_count, 'times' if invoke_count > 1 else 'time'))
# invoke_count += 1
print("Updating textvariable by changing variable choice {} {}"\
.format(choice_count, 'times' if choice_count > 1 else 'time'))
tk.Label(root, textvariable=choice).pack()
root.geometry("300x100")
root.mainloop()
print("This statement is after `mainloop()` and should print on closing window")