문제

I am trying to display images in a directory randomly in a single window that changes every 3 seconds. I also want it to be cross platform, as I am developing in Windows, but it will run on linux.

Currently I have this working code that iterates through all the image files of a directory with a mouse click (Code Below)

import os, sys, Tkinter, Image, ImageTk

def button_click_exit_mainloop (event):
    event.widget.quit()

root = Tkinter.Tk()
root.bind("<Button>", button_click_exit_mainloop)
root.geometry('+%d+%d' % (-5,-5)) #controls where the window is

#gets list of file names in certain directory. In this case, the directory it is in
dirlist = os.listdir('.') 

for f in dirlist:
    try:
        image1 = Image.open(f)
        root.geometry('%dx%d' % (image1.size[0],image1.size[1]))
        tkpi = ImageTk.PhotoImage(image1)
        label_image = Tkinter.Label(root, image=tkpi)
        label_image.place(x=0,y=0,width=image1.size[0],height=image1.size[1])
        root.mainloop() # wait until user clicks the window

    except Exception, e:
        pass

The way it does this however is when the mouse clicks on the window it calls a function to close the widget.

The problem I am having is how to call this function, or close the widget without an event. Any suggestions?

This is what I currently have. This doesn't work obviously because it is stuck in the root.mainloop(), but it shows what I have generally in mind (Code below)

import os, sys, Tkinter, Image, ImageTk, random

root = Tkinter.Tk()
root.geometry('+%d+%d' % (-5,-5)) #controls where the window is

#gets list of file names in certain directory. In this case, the directory it is in
dirlist = os.listdir('.') #might not be in order, CHECK!!!

while True:
    randInt = random.randint(0, 1)
    image = Image.open(dirlist[randInt])
    root.geometry('%dx%d' % (image.size[0],image.size[1]))
    tkpi = ImageTk.PhotoImage(image)
    label_image = Tkinter.Label(root, image=tkpi)
    label_image.place(x=0,y=0,width=image.size[0],height=image.size[1])
    root.mainloop()
    time.sleep(3)

Thank you!

-Jonathan

EDIT: Response to Bryan Oakley: I tried what you suggested, and this looks like the solution.

The function is being called every 3 seconds, and a window is being created, but the image is not being placed in the window.

Is it that I do not have access to the root? How do I gain access?

Here is what I have currently:

import os, sys, Tkinter, Image, ImageTk, random

def changeImage():
    #gets list of file names in certain directory. In this case, the directory it is in
    dirlist = os.listdir('.') #might not be in order, CHECK!!!

    #get random image
    randInt = random.randint(0, 1)
    image = Image.open(dirlist[randInt])

    #set size to show, in this case the whole picture
    root.geometry('%dx%d' % (image.size[0],image.size[1]))

    #Creates a Tkinter compatible photo image
    tkpi = ImageTk.PhotoImage(image)

    #Put image in a label and place it
    label_image = Tkinter.Label(root, image=tkpi)
    label_image.place(x=0,y=0,width=image.size[0],height=image.size[1])

    # call this function again in three seconds
    root.after(3000, changeImage)


root = Tkinter.Tk()
root.geometry('+%d+%d' % (-5,-5)) #controls where the window is

changeImage()

root.mainloop()

Thank you!!

SOLUTION EDIT: I did not change the code so the label is only created once, so a label is created with each call. I did not do this because this could be applied to many other variables (dirlist = os.listdir('.') for exmaple), but would make the code harder to read. I did not see any disadvantage other than maybe more cycles used? I did not see a memory increase over time, which is all that mattered to me.

Here is the code, thank you Bryan Oakley for helping me!!

import os, Tkinter, Image, ImageTk, random

def changeImage():
    global tkpi #need global so that the image does not get derefrenced out of function

    #gets list of file names in certain directory. In this case, the directory it is in
    dirlist = os.listdir('.')

    #get random image
    randInt = random.randint(0, 1)
    image = Image.open(dirlist[randInt])

    #set size to show, in this case the whole picture
    root.geometry('%dx%d' % (image.size[0],image.size[1]))

    #Creates a Tkinter compatible photo image
    tkpi = ImageTk.PhotoImage(image)

    #Put image in a label and place it
    label_image = Tkinter.Label(root, image=tkpi)
    label_image.place(x=0,y=0,width=image.size[0],height=image.size[1])

    # call this function again in 1/2 a second
    root.after(500, changeImage)

tkpi = None #create this global variable so that the image is not derefrenced

root = Tkinter.Tk()
root.geometry('+%d+%d' % (-5,-5)) #controls where the window is
changeImage()
root.mainloop()
도움이 되었습니까?

해결책

You need to remove your infinite loop -- tkinter already has one built-in. Instead, use after to periodically call a function:

def changeImage():
    <do whatever you want, such as swapping out images>

    # call this function again in three seconds
    root.after(3000, changeImage)

Then, in your main program you would call the function before calling mainloop:

root = Tkinter.Tk()
...
changeImage()
root.mainloop()

Also, you don't need changeImage to create a new label widget every time -- create the label once outside the function, and just change the image each time it is called.

다른 팁

All credit goes to BryanOakley for finding the root cause of the error. I cleaned up your code slightly. The imports also changed a little since I'm running Python3, but wanted to make sure it would work.

import os, sys, tkinter, random # N.B. tkinter not Tkinter in py3
from PIL import Image, ImageTk  # these are submodules in pillow py3

class Root(tkinter.Tk): # I buried this in a class. I prefer that for tkinter
    def __init__(self):
        super().__init__() # call Tk.__init__

        self.CYCLEDELAY = 3000 # 3 second per cycle

        # create and place the label once.
        self.image_label = tkinter.Label(self)
        self.image_label.place(x=0,y=0)

        # call our function
        self.changeImage()

    def changeImage(self):
        """Change the image on a delay"""
        dirlist = os.listdir('.')
        image = Image.open(random.choice(dirlist))
        # you had a funky method of getting a random member here. I cleaned it up

        i_width, i_height = image.size

        self.geometry("{}x{}".format(i_width,i_height))
        # change root's geometry using string formatting (preferred)

        self.image_label.configure(width=i_width, height=i_height)
        # change the label's geometry using string formatting

        self.tkpi = ImageTk.PhotoImage(image)
        self.image_label.configure(image=self.tkpi)
        # configure the label to use the PhotoImage

        self.after(self.CYCLEDELAY,self.changeImage)
        # loop!

root = Root()
root.mainloop()
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top