【问题标题】:Tkinter place widgets from a list using a loopTkinter 使用循环从列表中放置小部件
【发布时间】:2015-11-18 01:34:48
【问题描述】:

我正在尝试使用坐标列表在窗口上放置一堆标签。循环生成一堆标签对象并将它们附加到列表中。但是,当我尝试从对象列表中读取并对其运行命令时(pack()place()),屏幕上只显示最后调用的标签。

root = Tkinter.Tk()
...
coordinates = [[25, 40], [410, 40], [650, 40],
               [35, 180], [200, 180], [410, 180], [655, 180]]
labels = list()
interval = int()
message = "Hello, do you wanna push to master?".split(' ')
for index in range(len(coordinates)):
    if coordinates[index][1] < 100:
        labels.append(Tkinter.Label(root, text=message[index]))
    else:
        labels.append(Tkinter.Label(root, text=message[index]))
    root.after(interval, lambda: labels[index].place(x=coordinates[index][0], y=coordinates[index][1]))
    interval += 500

在上面的代码中,只有带有“master?”的标签将显示在屏幕上,尽管它以正确的样式出现在正确的坐标上。我可以通过使用range(len(coordinates) - 1range(len(coordinates) - 2 等更改最后一个索引来显示不同的标签,但一次只能显示一个。请注意,如果我手动将它们分配给变量并在没有循环的情况下调用它们,所有标签都可以正常显示。

【问题讨论】:

  • 这里的代码不修改就无法运行。请发布一个运行示例。
  • 代码运行正常,只需在顶部添加import Tkinter即可。

标签: python python-2.7 tkinter tk


【解决方案1】:

for 循环分配对index 的引用而不是

lambda: labels[index].place(x=coordinates[index][0], y=coordinates[index][1])` 

所以你需要lambda i=index:

lambda i=index: labels[i].place(x=coordinates[i][0], y=coordinates[i][1]))

我的版本

import Tkinter

coordinates = [[25, 40], [410, 40], [650, 40],
               [35, 180], [200, 180], [410, 180], [655, 180]]
message = "Hello, do you wanna push to master?".split(' ')

labels = []
interval = 0

root = Tkinter.Tk()
root.geometry("750x210")

for (x,y), msg in zip(coordinates, message):
    lab = Tkinter.Label(root, text=msg)
    labels.append(lab)
    root.after(interval, lambda a=x,b=y,l=lab:l.place(x=a, y=b))
    interval += 500

root.mainloop()

【讨论】:

  • 这行得通!但是,我不明白为什么为 lambda 添加参数会以这种方式工作。该函数无论如何都可以访问标签和索引,不是吗,因为它们是在更高的范围内定义的?
  • lambda 内部python 引用index - 不是来自index 的值。当调用lambda 时,Python 从index 获取值。同时index 发生了变化。在for 循环index == len(coordinates) == 7 之后,所以每个lambda 在labels[7].place(x=coordinates[7][0], y=coordinates[7][1]) 中使用相同的值7。 lambda i=index: 将值从index 复制到i 和所有lambda 使用不同的值。
【解决方案2】:

删除root.after,只保留这一行。

labels[index].place(x=coordinates[index][0], y=coordinates[index][1])

或者如果你真的想要延迟启动,然后删除lambda

【讨论】:

  • 我对 Tkinter 还很陌生。你能解释一下删除lambda 的作用吗?我试过了,它显示了所有元素,但都是一个接一个,而不是一个接一个交错。窗口显示的时间要晚得多。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-06-04
  • 2023-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多