嵌入在具有280个以上元素的画布中的Tkinter网格的意外行为

时间:2013-11-14 07:16:08

标签: python tkinter

我想显示很多缩略图,并且可以对它们执行不同的操作,具体取决于缩略图的内容。为此我从Adding a scrollbar to a group of widgets in Tkinter获取了示例,并将标签放在第一列中,将图像放在嵌入网格的第二列中。作为示例缩略图,您可以下载此image并将其重命名为160x120.jpg

import Tkinter as tk
from PIL import Image, ImageTk

class Example(tk.Frame):
    def __init__(self, root):

        tk.Frame.__init__(self, root)
        self.canvas = tk.Canvas(root, borderwidth=0, background="#ffffff")
        self.frame = tk.Frame(self.canvas, background="#ffffff")
        self.vsb = tk.Scrollbar(root, orient="vertical", command=self.canvas.yview)
        self.canvas.configure(yscrollcommand=self.vsb.set)

        self.vsb.pack(side="right", fill="y")
        self.canvas.pack(side="left", fill="both", expand=True)
        self.canvas.create_window((4,4), window=self.frame, anchor="nw", 
                                  tags="self.frame")

        self.frame.bind("<Configure>", self.OnFrameConfigure)

        self.photos = []
        self.imgs = []
        self.images = []
        self.lbls = []

        self.populate()

    def populate(self):
        '''Put in some fake data'''

        # n_thumbs = 100 : As expected, one label and one image per row.
        # n_thumbs = 300 : Images are only displayed up to the 278th.
        # n_thumbs = 600 : Just 63 images are displayed. Two labels per row.

        n_thumbs = 100

        for i in range(n_thumbs):
            lbl = tk.Label(self.frame, text="img " + str(i), width=10)
            lbl.grid(row=i, column=0)
            photo = Image.open("160x120.jpg")
            img = ImageTk.PhotoImage(photo)
            image = tk.Label(self.frame, image=img)
            image.grid(row=i, column=1)
            self.lbls.append(lbl)
            self.photos.append(photo)
            self.images.append(image)
            self.imgs.append(img)

    def OnFrameConfigure(self, event):
        '''Reset the scroll region to encompass the inner frame'''
        self.canvas.configure(scrollregion=self.canvas.bbox("all"))

if __name__ == "__main__":
    root=tk.Tk()
    Example(root).pack(side="top", fill="both", expand=True)
    root.mainloop()

现在,如果你设置n_thumbs = 100,一切都按预期工作,即每行有一个标签和一个图像。

如果设置n_thumbs = 300,则列表会突然以第278张图像结束。

如果设置n_thumbs = 600,则只会显示63张图像,但您仍然可以向下滚动到最后一张图像之外。此外,每行突然有两个标签。

如何解释这些影响?如何使用Tkinter在网格中显示超过300张图像?

1 个答案:

答案 0 :(得分:2)

我不知道一个事实,但我的猜测是你超过了tk画布的限制。对于120像素高的图像,您可以在包含帧超过32k(32767)像素高之前垂直显示272个图像。也许有一个硬限制,画布不能大于32767x32767。或者坐标可能被限制在-32767到+32767之间。如果你的一些缩略图不是120像素高,这可能解释了你所看到的限制278.我看到我的OSX系统的限制略有不同。

同样,我不知道这是事实,但似乎很可能。

如果这是一个硬限制,只需要做一点工作就可以一次只显示一个屏幕,只有当它们滚动到视图中时才会加载新图像(并且你可以销毁已滚出视图的图像)。并且,不是使用嵌入式框架,而是直接在画布上绘制图像。