【问题标题】:Placing Images in loop in Tkinter在 Tkinter 中循环放置图像
【发布时间】:2021-10-22 12:06:22
【问题描述】:

我正在尝试将一组图像放置在 Tkinter 中的水平行中。我通过遍历一个列表并从工作目录加载相应的图像来做到这一点。 我根据索引乘以一定的间距来放置图像。但是,当我实际放置图像时,它们都会在最后一个位置彼此重叠放置,而不是分开放置。计数值工作正常,当我 print(spacing*(count+1)) 时它输出正确的值,但是在放置时它们都被聚集在最后一个位置。

这是否与Label() 类有关?

for count, mood in enumerate(mood_options):
    mood_img = Image.open(f"img/{mood}.png")
    mood_img_copy = mood_img.resize(img_size, Image.ANTIALIAS)
    mood_img_resized = ImageTk.PhotoImage(mood_img_copy)
    mood_img_label = Label(root, image=mood_img_resized).place(relx=spacing*(count+1), rely=0.35)
    print(spacing * (count + 1))

编辑:我已经使用这种精确的方法来放置按钮,见下文:

for count, mood in enumerate(mood_options):
    mood_btn = Button(root, text=mood.capitalize(), command=lambda mood=mood: register_mood(mood), width=7) \
        .place(relx=(count + 1) * spacing, rely=0.5)

这完美无瑕,这让我想知道为什么它不适用于图像而不是按钮。

【问题讨论】:

  • 我建议您使用.pack.grid 以使放置更容易,因为您不需要计算任何东西并且Label 是一个类而不是一个函数
  • 在整个项目中我都在使用.place,并将其与.pack.grid 结合使用都行不通。
  • 首先你为什么使用.place?其次,pack 和其他任何一个布局管理器可以在同一个容器中同时使用
  • 我想我可以使用.place 更好地控制确切的位置。使用.pack,据我所知,您只能控制左侧、底部等。在迭代放置时使用.pack.place 相比似乎有点奇怪,因为可以选择确切的位置。
  • 这与图像被“捆绑”无关,这仅仅是因为除了最后一张之外,您的所有图像都被垃圾收集并且不复存在。您必须在其所需的整个生命周期内保留对 PhotoImage 对象的引用 - 但您在循环的每次迭代中都会覆盖 mood_img_resized

标签: python tkinter tkinter-label


【解决方案1】:

如果相同的逻辑适用于按钮,那么问题可能是图像被垃圾收集,在这种情况下,您不能将图像存储为某个类的属性来保存引用,因为在每次迭代中,每个图像都会被覆盖,仅参考最后一张图片。 global 也一样。所以去这里的方法是附加到一个列表中。尝试类似:

lst = []
for count, mood in enumerate(mood_options):
    mood_img = Image.open(f"img/{mood}.png")
    mood_img_copy = mood_img.resize(img_size, Image.ANTIALIAS)
    mood_img_resized = ImageTk.PhotoImage(mood_img_copy)
    lst.append(mood_img_resized)
    Label(root, image=mood_img_resized).place(relx=spacing*(count+1), rely=0.35)
    print(spacing * (count + 1))

虽然使用grid 以类似网格的方式放置东西会更好。如果您担心窗口的响应能力,请查看weight

from tkinter import *

root = Tk()

mood_options = ['a', 'b', 'c']
for count, mood in enumerate(mood_options):
    Label(root, text=mood).grid(row=0,column=count,padx=50)
    root.grid_columnconfigure(count,weight=1)

root.grid_rowconfigure(0,weight=1)

root.mainloop()

【讨论】:

  • 将布局管理器的返回值分配给变量有点毫无意义
  • @Matiiss 很好,我只是从原始代码中复制粘贴代码,已编辑
  • 为什么附加到列表会导致mood_img_resized 不被覆盖?
  • @Laurens 因为您将每个图像存储在一个列表中,并且没有一个被忽略或覆盖,所以列表中的每个图像都有一个引用
  • 这样就搞定了,谢谢你的帮助!
【解决方案2】:

您的spacing 是以像素为单位的实际空间量吗? 如果是这样,请不要使用relx,只使用xrelx 必须是介于 0.0 和 1.0 之间的浮点数。

【讨论】:

  • 我正在使用relx 在重新缩放窗口时保留相对位置。问题是我使用了完全相同的方法来放置按钮(使用 relx、间距、计数等),这很有效,但不知何故对于图像或标签不起作用。
  • 我刚刚检查过了,你的方法也适用于标签(只有文字,没有图像):from tkinter import * root = Tk() root.geometry('500x500') mood_options = ['a', 'b', 'c'] spacing = 0.25 for count, mood in enumerate(mood_options): mood_img_label = Label(root, text=mood).place(relx=spacing*(count+1), rely=0.35) print(spacing * (count + 1)) root.mainloop()
  • 是的,这就是为什么我觉得它令人困惑。我使用按钮(就像我以前做过的那样)和标签,但不是使用带有图像的标签。只是这样是不可能的还是我做错了?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多