在超过 280 个元素的画布中嵌入的 Tkinter 网格的意外行为 [英] Unexpected behavior of Tkinter's grid embedded in a canvas with more than 280 elements

查看:20
本文介绍了在超过 280 个元素的画布中嵌入的 Tkinter 网格的意外行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想显示很多缩略图,并且可以根据缩略图的内容对它们进行不同的操作.为此,我以 将滚动条添加到Tkinter 中的一组小部件,并在嵌入网格的第一列中放置标签,在第二列中放置图像.作为示例缩略图,您可以下载此 图像 并将其重命名到 160x120.jpg.

I want to display a lot of thumbnails and be able to do different operations on them, depending on the content of the thumbnail. For this I took the example from Adding a scrollbar to a group of widgets in Tkinter and put labels in the first column and images in the second column of the embedded grid. As a sample thumbnail you can download this image and rename it to 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,一切都按预期进行,即每行有一个标签和一个图像.

Now, if you set n_thumbs = 100, everything works as expected, i.e. there is one label and one image per row.

如果您设置 n_thumbs = 300,列表会突然以第 278 个图像结束.

If you set n_thumbs = 300, the list abruptly ends with the 278th image.

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

If you set n_thumbs = 600, only 63 images are shown, but you can still scroll down beyond the last image. Furthermore, suddenly there are two labels in each row.

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

How can these effects be explained? How can I display more than 300 images in a grid using Tkinter?

推荐答案

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

I don't know for a fact, but my guess is that you're exceeding the limits of the tk canvas. With an image 120 pixels tall, you can display 272 images vertically before the containing frame exceeds 32k (32767) pixels tall. Perhaps there is a hard limit that the canvas can't be bigger than 32767x32767. Or maybe coordinates are constrained to be from -32767 to +32767. If some of your thumbnails weren't exactly 120 pixels tall, that might explain the limit you're seeing of 278. I was seeing a slightly different limit on my OSX system.

再说一次,我不知道这是一个事实,但似乎很有可能.

Again, I don't know that for a fact, but it seems likely.

如果这是一个硬性限制,只需稍加工作,您一次只能显示一整屏,并且只有在滚动到视图中时才加载新图像(并且您可以销毁已滚动到视图之外的图像).而且,不使用嵌入的框架,而是直接在画布上绘制图像.

If this is a hard limit, with a little work you can only show a screenful at a time, and load new images only when they are scrolled into view (and you can destroy images that have scrolled out of view). And, instead of using an embedded frame, draw the images directly on the canvas.

这篇关于在超过 280 个元素的画布中嵌入的 Tkinter 网格的意外行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆