在运行时使用函数向笔记本添加标签 - 我可以创建标签及其内部框架,但不能向框架添加组件

问题描述

@H_404_0@我从原始代码中定义的笔记本开始,它有 4 个选项卡,每个选项卡都有一个关联的 Frame(Tab1 有一个名为 page1 的 Frame,Tab2 有 page2,依此类推)。对于前两个选项卡,我有在每一帧中放置一个画布并在该画布上绘制图形的函数。所以我可以在运行时在代码中将项目放置在这些预定义的标签页上。

@H_404_0@我的目标是能够在笔记本中放置额外的、计划外的标签,使用功能,然后将信息放置在与新标签关联的页面上。

@H_404_0@我有一个函数 Command3() - 见下文 - 我在其中即时创建选项卡。

@H_404_0@'''

def command3():
    #command invoked by button 3 - add a tab to the notebook
    tab_caption = simpledialog.askstring('Tab Text','Enter Text for Tab')
    ntn = len(nb.tabs()) + 1
    if tab_caption == '':
        tab_caption = 'Tab ' + str(ntn)
    var_name = 'page' + str(ntn)
    command_string = var_name + ' = tk.Frame(nb)'
    exec(command_string)
    command_string = 'nb.add('+var_name+',text = tab_caption)'
    exec(command_string)
@H_404_0@'''

@H_404_0@上面的代码工作得很好。当我执行此代码(通过单击 Button3)时,我会得到一个新选项卡,其中包含我在对话框中提供的文本,该对话框具有一个名为“第 5 页”的内部框架。我可以点击选项卡并选择它(它什么都不显示,因为我没有在那里放置任何东西),我什至可以在代码中更改选项卡的名称

@H_404_0@我的问题是,当我尝试在“第 5 页”上放置任何内容时,什么也没有出现。下面的函数 Command4 旨在将标签放置在页面上的任何位置。

@H_404_0@'''

 def command4():

    #command invoked by button 4 - add label
    last_tab = len(nb.tabs())
    last_tab_index = last_tab-1
    page_name = 'page' + str(last_tab)
    nb.tab(last_tab_index,text = 'Repeat Graph')
    print(last_tab)
    print(last_tab_index)
    print(page_name)

    labelTest = tk.Label(page5,text = 'Something')
    labelTest.pack()
@H_404_0@''' 当这段代码执行时,选项卡名称发生变化,打印语句全部起作用,最后两行似乎没有错误地执行,但在 Tab5 的框架中没有任何显示(框架是 page5)。

@H_404_0@Python 似乎知道第 5 页存在(当我终止程序并在 Idle 中键入 >>> page 5 时,我得到 。所以命令 3 似乎已经工作并创建了适当的 Frame 对象。

@H_404_0@我的目的是计算“页面名称,以便我可以重复执行此操作并使用如下代码

@H_404_0@'''

 def command4():

    #command invoked by button 4 - add label
    last_tab = len(nb.tabs())
    last_tab_index = last_tab-1
    page_name = 'page' + str(last_tab)
    nb.tab(last_tab_index,text = 'Repeat Graph')
    print(last_tab)
    print(last_tab_index)
    print(page_name)

    command_string = "labelTest = tk.Label(" + page_name + ",text = 'Something')"
    exec(command_string) 
    labelTest.pack()
@H_404_0@'''

@H_404_0@当我执行此代码时,exec(command_string) 不会产生任何错误,但是,当软件执行 labelTest.pack() 命令时,我收到一个错误,指出名称 labelTest 未定义。

@H_404_0@这是范围问题吗?有没有另一种方法来处理这个问题?有没有办法使用内部的“.!frame2.!notebook.!frame5”符号来完成同样的事情?

解决方法

你不需要使用exec,你可以简单地使用一个局部变量。在这件事上使用 exec 几乎从来都不是正确的做法。

例如:

def command3():
    tab_caption = simpledialog.askstring('Tab Text','Enter Text for Tab')
    ntn = len(nb.tabs()) + 1
    if tab_caption == '':
        tab_caption = 'Tab ' + str(ntn)
    tab_frame = tk.Frame(nb)
    nb.add(tab_frame,text=tab_caption)

    # inside the function you can add other widgets
    label = tk.Label(tab_frame,text="Hello,world")
    label.pack()

如果您想在函数外的框架中添加项目,请让函数返回框架。

def command3():
    ...
    return tab_frame

然后,在调用 command3 的代码中,您可以通过返回的框架添加小部件:

new_tab_frame = command3()
label = tk.Label(new_tab_frame,world")

您几乎可以在任何地方使用 tabs 方法返回的值。但是,该方法返回内部小部件的名称,必须将其转换为实际小部件才能使用:

last_frame = nb.nametowidget(nb.tabs()[-1])
label = tk.Label(last_frame,...) 

如果您更喜欢象征性地引用选项卡(即:按名称而不是按索引),您可以将框架存储在字典中:

frames = {}
def command3():
    #command invoked by button 3 - add a tab to the notebook
    tab_caption = simpledialog.askstring('Tab Text','Enter Text for Tab')
    ntn = len(nb.tabs()) + 1
    if tab_caption == '':
        tab_caption = 'Tab ' + str(ntn)
    tab_frame = tk.Frame(nb)
    frames[tab_caption] = tab_frame
    nb.add(tab_frame,text=tab_caption)
...
# add a label to the tab named "Tab 1":
tab_frame = frames["Tab 1"]
label = tk.Label(tab_frame,...)