按名称访问窗口的子窗口小部件?

时间:2018-01-22 15:27:22

标签: python tkinter widget children

Python / tkinter中是否有任何方法可以访问由变量名引用的子元素,但是来自其他函数?

例如,在VBA中,可以通过其名称直接引用其他窗口的元素。 例如,如果我有两个窗口,UserForm1UserForm2,我可以点击Label1上的按钮更改UserForm2 UserForm1的文本值。

Private Sub CommandButton1_Click()
  UserForm2.Label1.Caption = "Changed"
End Sub

在tkinter中,我找到winfo_children()来访问子元素。有没有办法通过他们的名字访问它们?

请参阅下面的示例代码:

import tkinter
from tkinter import *

#----------------------------------------------------------------------
def new(parent_window):
    """"""
    parent_window.withdraw()
    global main_window
    global new_window
    new_window = tkinter.Tk()
    new_window.title("My App - New")

    label1 = tkinter.Label(new_window, text="NEW")
    label1.grid(row=0,column=0,columnspan=3,pady=10,padx=10, sticky="nsw")

    b1 = tkinter.Button(new_window, text="Change It", command=lambda: showdashboard(new_window))
    b1.grid(row=4,column=1,padx=20,pady=10,sticky="nwse")

    b2 = tkinter.Button(new_window, text="Quit", command=lambda: quit())
    b2.grid(row=5,column=1,padx=20,pady=10,sticky="nwse")

#----------------------------------------------------------------------
def dashboard(parent_window):
    """"""
    parent_window.withdraw()
    global main_window
    global dashboard_window
    dashboard_window = tkinter.Tk()
    dashboard_window.title("My App - Dashboard")

    label1 = tkinter.Label(dashboard_window, text="Dashboard")
    label1.grid(row=0,column=0,columnspan=3,pady=10,padx=10, sticky="nsw")

    b1 = tkinter.Button(dashboard_window, text="New", command=lambda: new(dashboard_window))
    b1.grid(row=4,column=1,padx=20,pady=10,sticky="nwse")

#----------------------------------------------------------------------
def showdashboard(parent_window):
    """"""
    parent_window.withdraw()
    dashboard_window.update()
    dashboard_window.deiconify()
    #This way it works <<<<<<<<<<<<<<------!!!!!!!
    byID=dashboard_window.winfo_children()
    byID[0].config(text="change the value")
    #But I am looking for somethin like this <<<<<<<<<<<<<<------????
    dashboard_window.label1.config(text="changed the value")

#----------------------------------------------------------------------
main_window=tkinter.Tk()
main_window.title("MyApp")

label = tkinter.Label(main_window, text="My App")
label.grid(row=0,column=0,pady=10,padx=10,sticky="nwse")

b1 = tkinter.Button(main_window, text="Dashboard", command=lambda:dashboard(main_window))
b1.grid(row=1,column=0,padx=20,pady=10,sticky="nwse")

main_window.mainloop()

3 个答案:

答案 0 :(得分:0)

我不确定名称的含义是什么:

  

“Python / tkinter中是否有任何方法可以访问其名称引用的子元素?”

您只需通过对象引用访问小部件:

# Procedural
import tkinter as tk


def change():
    object_reference['text'] = "Changed!"

root = tk.Tk()
object_reference = tk.Label(root, text="This is a label for root-window")
object_reference.pack()

another_window = tk.Toplevel(root)
btn_in_other_window = tk.Button(another_window, text="Change")
btn_in_other_window['command'] = change
btn_in_other_window.pack()

root.mainloop()

或者如果要使用更多面向对象的方法来定义它们,则可以使用.(点)表示法:

#oop
import tkinter as tk


class App1(tk.Toplevel):
    def __init__(self, master):
        super().__init__()

        self.label = tk.Label(self, text="This is App1's label")
        self.label.pack()


class App2(tk.Toplevel):
    def __init__(self, master):
        super().__init__(master)

        self.button = tk.Button(self, text="This is a App2's button")
        self.button.pack()


def change(label):
    label['text'] = "Changed!"


if __name__ == '__main__':
    root = tk.Tk()
    root.withdraw()

    app1 = App1(root)
    app2 = App2(root)
    app2.button['command'] = lambda label=app1.label: change(label)

    root.mainloop()

答案 1 :(得分:0)

winfo_children()返回与小部件类型相关联的class实例以及tkinter分配给实际tk对象的名称。

这意味着是的,我们可以参考小部件的名称,虽然我不确定除了不需要将标签分配给变量之外,这会给你带来什么好处。

from tkinter import *

root = Tk()

Label(root, text="Label1").pack()
label2 = Label(root, name="name", text="Label2")

label2.pack()

print(root.winfo_children())
print(root.nametowidget('.!label'))
print(str(label2))

Button(root, text="Delete label2", command=lambda: root.nametowidget(".name").destroy()).pack()

以上操作会导致窗口中出现两个Label窗口小部件和一个Button窗口小部件。第一个Label没有存储在变量中,但我们可以很乐意在print语句中调用它。第二个存储在变量中,但您可以看到command中的Button我们没有引用变量,而是引用Label的名称属性。

Bryan Oakley has a fantastic answer here explaining this.

答案 2 :(得分:0)

不是您问题的确切答案,因为正如评论中所述

不过,可以通过以下方式获取元素窗口的子窗口小部件的列表:

root.update()
lista = list(root.children.values()) 

然后可以引用列表元素,并使用窗口小部件本身执行任何操作。例如,要获取第一个小部件的宽度,请执行print(lista[0].winfo_width())

警告:我不确定列表中的元素顺序与小部件在脚本中的显示顺序相同,尽管对我来说是按此顺序进行的。希望有人在评论中写。