嵌套的tkinter命令功能如何工作?

问题描述 投票:0回答:1

代码示例来自this answer

[单击带有命令功能的按钮(此命令功能本身将调用另一个菜单命令功能),如代码示例所示,会发生什么?单击Refresh menu时,为什么未激活lambda command show()

为清楚起见,我对原始代码进行了如下更改:

  • 注释Button().invoke
  • 添加一些print()信息
  • 并更改/添加一些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")
button tkinter menu command
1个回答
-1
投票

这不应该是最佳的答案,而是问题所有者的实验记录。我的初步结论是在step 1 and 2处,并采取以下步骤进行分析确认。

这里是使用python 3.7.5TkVersion 8.6运行的结果:

  1. 使用终端命令python tk_dynamic.py运行以进行初始化。标准输出:
Before adding cascade menu(id 4382568272) to root menubar(id 4382495440)
Updating textvariable by changing variable choice 0 time

目前,我们尚未调用Button command,因此cascade menu中没有任何内容。并且root menubar label被初始化为Choice。单击它,没有下拉菜单提示。![enter image description here

  1. 单击Refresh menu,现在通过下拉菜单root menubar labelChoice重置为['one', 'two', 'three'](刷新初始label_cascade = ['dummy']时,我们转到2ndif-else分支]语句。)

注意,目前我们尚未在循环中调用lambada command,并且choice change count不会更改。

Update root menubar(id 4382495440) and set label as `Choice` 1 time in `refresh()`
Add command #1 to cascade menu(id 4382568272) by calling show() at refresh count 1
Choice change count is 0 when adding command #1 at refresh count 1
Add command #2 to cascade menu(id 4382568272) by calling show() at refresh count 1
Choice change count is 0 when adding command #2 at refresh count 1
Add command #3 to cascade menu(id 4382568272) by calling show() at refresh count 1
Choice change count is 0 when adding command #3 at refresh count 1

enter image description here

    再次
  1. 单击Refresh menu。请注意,choice change count仍为0。但是由于在此刷新时间['four', 'five', 'six', 'seven']处的label_cascade[0] = 'one',下拉菜单更改为2
Update root menubar(id 4382495440) and set label as `Choice` 2 times in `refresh()`
Add command #1 to cascade menu(id 4382568272) by calling show() at refresh count 2
Choice change count is 0 when adding command #1 at refresh count 2
Add command #2 to cascade menu(id 4382568272) by calling show() at refresh count 2
Choice change count is 0 when adding command #2 at refresh count 2
Add command #3 to cascade menu(id 4382568272) by calling show() at refresh count 2
Choice change count is 0 when adding command #3 at refresh count 2
Add command #4 to cascade menu(id 4382568272) by calling show() at refresh count 2
Choice change count is 0 when adding command #4 at refresh count 2

enter image description here

  1. 单击下拉命令four,根菜单栏标签更改为Choice is: four,新的可见标签four将在按钮Refresh menu下方提示。每次我们单击dropdown command时,choice count将为+1
Update root menubar(id 4382495440)'s label as `Choice is: four`
        when adding command #1 to cascade menu(id 4382568272) at refresh count 2 in `show()`
Reset `variable choice` 1 time as four in show() when adding command #1

enter image description here

  1. 单击seven,根菜单栏标签更改为Choice is: seven,新的可见标签seven将在按钮Refresh menu下方提示。
  2. 请注意,command #4表示sevenlabel_cascade中的4th

项目,即refresh() loop中要处理的最后一个项目。如果我们多次单击seven,则command #4保持不变,并且choice count继续增加。
Update root menubar(id 4382495440)'s label as `Choice is: seven`
        when adding command #4 to cascade menu(id 4382568272) at refresh count 2 in `show()`
Reset `variable choice` 2 times as seven in show() when adding command #4
Update root menubar(id 4382495440)'s label as `Choice is: seven`
        when adding command #4 to cascade menu(id 4382568272) at refresh count 2 in `show()`
Reset `variable choice` 3 times as seven in show() when adding command #4

enter image description here

  1. 单击Refresh menu,将choice count重置为0,将根菜单栏标签重置为Choice,其下拉菜单切换为['one', 'two', 'three']。注意refresh count将继续增加,并且当前循环的迭代时间为3
  2. Update root menubar(id 4382495440) and set label as `Choice` 3 times in `refresh()`
    Add command #1 to cascade menu(id 4382568272) by calling show() at refresh count 3
    Choice change count is 0 when adding command #1 at refresh count 3
    Add command #2 to cascade menu(id 4382568272) by calling show() at refresh count 3
    Choice change count is 0 when adding command #2 at refresh count 3
    Add command #3 to cascade menu(id 4382568272) by calling show() at refresh count 3
    Choice change count is 0 when adding command #3 at refresh count 3
    

enter image description here

  1. 关闭窗口,然后激活最后一个print()
  2. This statement is after `mainloop()` and should print on closing window
    
© www.soinside.com 2019 - 2024. All rights reserved.