如何让我的 tkinter 图片查看器工作?

How do I get my tkinter picture viewer working?

我一直在尝试自学 tkinter 并想制作一个程序来查找文件夹的目录和子目录中的所有图片,然后用一个按钮一张一张地显示它们以保存将文件放入 "Yes"、"Maybe" 或 "Skip" 文件夹或直接删除文件。

这是我试图让它看起来像的东西:

这是我的代码,它试图做到这一点:

# Python 3.4

import os
import tkinter as tk
from tkinter import Frame, Button
from PIL import Image, ImageTk
from send2trash import send2trash

tk_root = tk.Tk()
tk_root.title("Picture Viewer - Do I want to keep this picture?")
file_count = 0

p = path = 'C:\Users\MyUserName\Desktop\Test\'
yes = lambda img: os.rename(img, p+'Yes\Picture_{0}.jpg'.format(file_count))
maybe = lambda img: os.rename(img, p+'Maybe\Picture_{0}.jpg'.format(file_count))
skip = lambda img: os.rename(img, p+'Skipped\Picture_{0}.jpg'.format(file_count)) 
delete = lambda img: send2trash(img) # Note: os.remove('img.jpg') also works

def search(directory):
    global file_count
    for root, subdirs, files in os.walk(directory):
        for file in files:
            if os.path.splitext(file)[1].lower() in ('.jpg', '.jpeg'):
                img = os.path.join(root, file)
                file_count += 1

                top_frame = Frame(tk_root)
                bottom_frame = Frame(tk_root)
                top_frame.pack(side='top')
                bottom_frame.pack(side='bottom')

                picture = ImageTk.PhotoImage(Image.open(img))
                picture = tk.Label(tk_root, image=picture)
                picture.pack(side='top')

                button_yes = Button(top_frame, text="Yes", command=lambda x=img:yes(x))
                button_maybe = Button(top_frame, text="Maybe", command=lambda x=img:maybe(x))
                button_skip = Button(top_frame, text="skip", command=lambda x=img:skip(x))
                button_delete = Button(bottom_frame, text="Delete", command=lambda x=img:delete(x))

                button_yes.pack(side='left')
                button_maybe.pack(side='left')
                button_skip.pack(side='left')
                button_delete.pack(side='bottom')
    print('All done!')
search('Test')

但是,问题是在我启动程序后它根本无法正常工作。它只是将第一张图片“1.jpg”移动到我选择(或删除)的任何文件夹中,如果我尝试对另一张图片进行排序,则会出现以下错误:

FileNotFoundError: [WinError 2] The system cannot find the file specified: 'Test\Example.jpg' -> 'C:\Users\Vale\Desktop\Test\Maybe.jpg'

也许最重要的是图像没有正确显示和循环。每次都只是中间的一个灰色框。如何让我的程序运行?我知道我需要让图像看起来静止并且需要做一些事情才能让程序也移动到下一张图片(所以我不会因为尝试对同一张图片进行两次排序而得到 FileNotFoundError),但是在观看教程和阅读文档后,我不确定该怎么做。

正如 BlackJack 所提到的,您的代码一遍又一遍地创建 GUI 小部件。您需要将其从循环中移出。另外,为了在 Label 中显示图像,您不能同时使用 picture 作为 ImageTk 对象和 Label 对象的名称。

修改建议。您可以使用生成器来获取图像 path/filename。并制作常规函数而不是使用 lambda。我有兴趣了解它是如何工作的,所以我根据您的代码制作了下面的程序。当我测试它时,我有不同的路径,在 OSX 上工作,所以没有用你的 Windows 路径(我在此处放入代码中)对其进行测试。

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

tk_root = tk.Tk()
tk_root.title("Picture Viewer - Do I want to keep this picture?")
file_count = 0

p = path = 'C:\Users\MyUserName\Desktop\Test\'


def search(directory):
    global file_count
    for root, subdirs, files in os.walk(directory):
        for file in files:
            if os.path.splitext(file)[1].lower() in ('.jpg', '.jpeg'):
                img = os.path.join(root, file)
                file_count += 1
                yield img


def next_image():
    try:
        global photo_path
        photo_path = next(path_generator)
        photo = ImageTk.PhotoImage(Image.open(photo_path))
        picture.configure(image=photo)
        picture.image = photo
    except StopIteration:
        picture.configure(image='', text='All done!')


def move_file(directory):
    if not os.path.exists(directory):
        os.makedirs(directory)
    new_file = directory + 'Picture_{0}.jpg'.format(file_count)
    os.rename(photo_path, new_file)


def yes():
    move_file(path + 'Yes\')
    next_image()


def maybe():
    move_file(path + 'Maybe\')
    next_image()


def skip():
    move_file(path + 'Skipped\')
    next_image()


def delete():
    # Code for deleting file here
    next_image()

top_frame = Frame(tk_root)
bottom_frame = Frame(tk_root)
top_frame.pack(side='top')
bottom_frame.pack(side='bottom')

path_generator = search(p)
photo_path = next(path_generator)

photo = ImageTk.PhotoImage(Image.open(photo_path))
picture = tk.Label(tk_root, image=photo)
picture.image = photo
picture.pack(side='top')

button_yes = Button(top_frame, text="Yes", command=yes)
button_maybe = Button(top_frame, text="Maybe", command=maybe)
button_skip = Button(top_frame, text="skip", command=skip)
button_delete = Button(bottom_frame, text="Delete", command=delete)

button_yes.pack(side='left')
button_maybe.pack(side='left')
button_skip.pack(side='left')
button_delete.pack(side='bottom')

tk_root.mainloop()

编辑:

此代码的一个问题似乎是它遍历子目录(是的,可能,已跳过)。因此,如果图像在路径中然后移动,您将看到两次图像。

如果不想遍历Yes、Maybe和Skipped文件夹,可以将search函数改为:

def search(directory):
    global file_count
    excludes = ['Yes', 'Maybe', 'Skipped']
    for root, subdirs, files in os.walk(directory, topdown=True):
        subdirs[:] = [d for d in subdirs if d not in excludes]
        for file in files:
            if os.path.splitext(file)[1].lower() in ('.jpg', '.jpeg'):
                img = os.path.join(root, file)
                file_count += 1
                yield img