2

I want to make image sorter in tkinter: There would be image in the center 2 buttons in the bottom ["one; two"] and when I will press first button that image will go to the folder "one"

I have tried many variants but cant solve this problem; here is example

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

size= 700, 700

window = tk.Tk()
window.title("Join")
window.geometry("700x700")
window.minsize(700,700)
window.maxsize(700,700)

bottomFrame = tk.Frame(window)
bottomFrame.pack(fill=tk.X, side=tk.BOTTOM)

for i in range(2):
    bottomFrame.columnconfigure(i, weight=1)

#commands
def one():
    print("one")
    im.save("one/"+ path)

def two():
    print("two")
    im.save("two/"+ path)

#loop

imagesList = listdir("all/")

for path in imagesList:

    print("test")

    im = Image.open("all/" + path)

    im.thumbnail(size, Image.ANTIALIAS)

    img = ImageTk.PhotoImage(im)

    label = tk.Label(window, image = img)

    label.pack(side = "top", fill = "both", expand = "true")

    bluebutton = tk.Button(bottomFrame, text="one", fg="blue", command=one)
    bluebutton1 = tk.Button(bottomFrame, text="two", fg="blue", command=two)

    bluebutton.grid(row=0, column=0, sticky=tk.W+tk.E)
    bluebutton1.grid(row=0, column=1, sticky=tk.W+tk.E)

    window.mainloop()
Pypet
  • 41
  • 5
  • 2
    _"cant solve this problem"_ - why can't you? What happens when you try? Do you get an error, and if so, what is the error? Do you not get an error, but the image doesn't show? Does it show the wrong image? Something else? – Bryan Oakley Aug 04 '21 at 19:35
  • where does `path` from one/two functions come from ? – Cyril Jouve Aug 04 '21 at 19:53

2 Answers2

2

You were close! The problem is in your functions one and two

Note that I've used global variables here so that I didn't have to change your code much - you should wrap this in a class and have the variables be references as members, using self

def one():
    global im, img, label
    print("one")
    # can't do this, or you'll overwrite the image!
    #im.save("one/"+ path)
    im = Image.open("one/" + path)

    im.thumbnail(size, Image.ANTIALIAS)

    img = ImageTk.PhotoImage(im)
    label.configure(image=img)

def two():
    global im, img, label
    print("two")
    # can't do this, or you'll overwrite the image!
#    im.save("two/"+ path)
    im = Image.open("two/" + path)

    im.thumbnail(size, Image.ANTIALIAS)

    img = ImageTk.PhotoImage(im)
    label.configure(image=img)

Let's explain why:

  • mainloop is a "blocking" call; the program halts at this point

  • button presses are specially designed to trigger functions even during this block. This type of "asynchronous" design is typical in UIs

  • so the part of the code that loads the image, this part:

    im = Image.open("all/" + path)

    im.thumbnail(size, Image.ANTIALIAS)

    img = ImageTk.PhotoImage(im)

    was only ever getting called once

  • you would "save" the image in functions one and two but it isn't clear what that is intended to do. It looks like it just overwrites the image in one/two with the one from all. Note that the variable path is just coincidentally getting set properly in that function because it's finding a global variable. You should probably pass that in directly

Instead, we can simply open the image from path one or two, and then use configure to change the image displayed on the label. Note that you usually need to keep some references around to Image and ImageTk objects when your program gets nontrivial, otherwise the garbage collector might start trashing your pictures before you can see them

en_Knight
  • 5,301
  • 2
  • 26
  • 46
1

First you should not create the label and buttons and run mainloop() inside the for loop. You should create the label and buttons in the main block and run mainloop() in the main block as well.

Then you need to create a function to show the next image. The function should be executed inside one() and two() after saving the image to the folder you want.

Below is the modified code:

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

size= 700, 700

window = tk.Tk()
window.title("Join")
window.geometry("700x700")
window.minsize(700,700)
window.maxsize(700,700)

bottomFrame = tk.Frame(window)
bottomFrame.pack(fill=tk.X, side=tk.BOTTOM)

for i in range(2):
    bottomFrame.columnconfigure(i, weight=1)

#commands
def next_image():
    global im, img, path
    if len(imagesList) > 0:
        path = imagesList.pop(0) # extract a image path from the list
        im = Image.open(src_dir + path)
        im.thumbnail(size, Image.ANTIALIAS)
        img = ImageTk.PhotoImage(im)
        label.config(image=img)
    else:
        label.config(text="No more image!", image="")

def one():
    print("one")
    im.save("one/"+path)
    next_image() # show next image

def two():
    print("two")
    im.save("two/"+path)
    next_image() # show next image

src_dir = "all/"
imagesList = listdir(src_dir) # load the image list

# label for showing the image
label = tk.Label(window)
label.pack(side = "top", fill="both", expand="true")

bluebutton = tk.Button(bottomFrame, text="one", fg="blue", command=one)
bluebutton1 = tk.Button(bottomFrame, text="two", fg="blue", command=two)

bluebutton.grid(row=0, column=0, sticky=tk.W+tk.E)
bluebutton1.grid(row=0, column=1, sticky=tk.W+tk.E)

# show the first image
next_image()
window.mainloop()

It is recommended to use shutil.move() function to move those image files instead of im.save():

import shutil
...
def one():
    print("one")
    #im.save("one/"+path)
    shutil.move(src_dir+path, "one/")
    next_image()

def two():
    print("two")
    #im.save("two/"+path)
    shutil.move(src_dir+path, "two/")
    next_image()
...
acw1668
  • 40,144
  • 5
  • 22
  • 34