首页 > 解决方案 > 为什么我的 tkinter 标签上的文件夹中的所有图像都没有显示在画布上的框架内?

问题描述

我正在编写一个 python tkinter 脚本,以从 opencv 创建的文件夹中检索 .jpg 文件,并以水平方式将所有这些文件彼此相邻显示。我可以让代码工作,因为它显示 jpg 文件彼此相邻。然而,在一些帧之后,tkinter 将一个 jpg 文件放在另一个之上,直到最后一个 jpg 文件。不知道我做错了什么。下面是我的脚本。任何建议表示赞赏。

import os
import sys
from Tkinter import *
from PIL import Image, ImageTk
import tkFileDialog

path = 'C:\\JPEGs'
images = []

for dirname, dirnames, filenames in os.walk(path):
    for filename in filenames:
        file = os.path.join(dirname, filename)
        if '.jpg' in file.lower() :
            images.append(file)

images.sort(key=lambda f: int(filter(str.isdigit, f)))
#print images
## Main window
root = Tk()
root.geometry('1280x720')
root.title("VIDYOANALYSER-Sachin Chandrashekar")
root.wm_iconbitmap('ad1.ico')
## Grid sizing behavior in window
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
# Canvas
cnv = Canvas(root,bg="light yellow")
cnv.grid(row=0, column=0, sticky='nswe')

## Scrollbars for canvas
hScroll = Scrollbar(root, orient=HORIZONTAL, command=cnv.xview)
hScroll.grid(row=1, column=0, sticky='we')
vScroll = Scrollbar(root, orient=VERTICAL, command=cnv.yview)
vScroll.grid(row=0, column=1, sticky='ns')
cnv.configure(xscrollcommand=hScroll.set, yscrollcommand=vScroll.set)
# Frame in canvas
frm = Frame(root,bg="light yellow")


## This puts the frame in the canvas's scrollable zone
cnv.create_window(0, 0, window=frm, anchor='nw')
## Frame contents
columnCount=0

for files in images:
    im = Image.open(files)
    tkimage = ImageTk.PhotoImage(im)
    myvar=Label(frm,image = tkimage,text=str(os.path.basename(files).strip('.jpg')), compound=TOP,bg='sky blue',relief=SUNKEN)
    myvar.image = tkimage
    myvar.grid(row=0, column=columnCount, sticky='nswe')
    myvar.grid_rowconfigure(0, weight=1)
    myvar.grid_columnconfigure(0, weight=1)
    columnCount += 1



## Update display to get correct dimensions
frm.update_idletasks()
myvar.update_idletasks()
## Configure size of canvas's scrollable zone
cnv.configure(scrollregion=(0, 0, frm.winfo_width(), frm.winfo_height()))

## Go!
root.mainloop()

预期:有 253 个 jpeg 文件,我希望显示所有帧。检查链接 - https://i.stack.imgur.com/BRMTy.png 实际:仅显示 243 个文件,其余帧显示在另一个上方,只有最后一帧(裁剪一半)在UI.Check 链接 - https://i.stack.imgur.com/KqMeL.png

标签: pythonpython-2.7tkinter

解决方案


正如@Jasonharper 指出的那样, tkinter 在这种情况下使用 16 位坐标。(不确定这是否对所有容器都相同)

我已经修改了您的代码以包含一些测量值,以便我们可以看到我们的总图像大小与总标签大小的比较。

我添加了 2 个变量:

total_image_size = 0
total_widget_size = 0

然后在创建所有小部件时,我检查每个图像的大小并更新total_image_size

然后我遍历框架中的所有小部件以获取它们的宽度winfo_width()并更新total_widget_size

然而,我们必须运行这个程序两次。第一次查看在开始堆叠图像之前显示了多少图像,第二次在更新计算小部件的循环之后查看小部件的大小,因为我们不想计算小部件的宽度堆叠的小部件。

通过下面的代码,您可以看到 16 位坐标限制是准确的,因为在堆叠之前放置的最后一个小部件将总宽度设置为 32736。如果我们考虑下图中显示的小间隙,我们可以说高限制所在的准确度。

我的测试图像测量为 82 像素宽,小部件测量为每个图像/小部件 88 像素宽。

结论

根据您的需要,仅加载大量图像列表可能无法在此处工作,但是如果您使用列表来存储图像或图像路径,则可以使用比例滚动它们并将它们动态加载到 from 中以绕过此限制。

结果

在此处输入图像描述

代码

import os
import tkinter as tk
from PIL import Image, ImageTk


path = r'complete\file\path\here'
images = []
total_image_size = 0
total_widget_size = 0
for dirname, dirnames, filenames in os.walk(path):
    for filename in filenames:
        file = os.path.join(dirname, filename)
        images.append(file)

tk.Tcl().call('lsort', '-dict', images)

root = tk.Tk()
root.geometry('1280x720')
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
cnv = tk.Canvas(root,bg="light yellow")
cnv.grid(row=0, column=0, sticky='nswe')

hScroll = tk.Scrollbar(root, orient='horizontal', command=cnv.xview)
hScroll.grid(row=1, column=0, sticky='we')
vScroll = tk.Scrollbar(root, orient='vertical', command=cnv.yview)
vScroll.grid(row=0, column=1, sticky='ns')
cnv.configure(xscrollcommand=hScroll.set, yscrollcommand=vScroll.set)
frm = tk.Frame(root, bg="light yellow")
cnv.create_window(0, 0, window=frm, anchor='nw')
columnCount = 0

for files in images:
    im = Image.open(files)
    width, height = im.size
    total_image_size += width
    tkimage = ImageTk.PhotoImage(im)
    myvar = tk.Label(frm, image=tkimage, text=str(os.path.basename(files).strip('.jpg')),
                  compound='top', bg='sky blue', relief='sunken')
    myvar.image = tkimage
    myvar.grid(row=0, column=columnCount, sticky='nswe')
    myvar.grid_rowconfigure(0, weight=1)
    myvar.grid_columnconfigure(0, weight=1)
    columnCount += 1


frm.update_idletasks()
cnv.configure(scrollregion=(0, 0, frm.winfo_width(), frm.winfo_height()))


def do_thing():
    global total_widget_size
    for ndex, widget in enumerate(frm.winfo_children()):
        if ndex <= 371:  # set the last image to be loaded before stacking started.
            total_widget_size += widget.winfo_width()
    print('Total widget width prior to stacking', total_widget_size)


print('Total image width', total_image_size)
# short delay so we can check size after all images have been loaded.
# If it takes longer than 3 seconds for your app to load then change this time to be more.
root.after(3000, do_thing)
root.mainloop()

使用的测试图像:

在此处输入图像描述


推荐阅读