使用Tkinter随机显示带有一个窗口的图像

时间:2014-05-09 16:33:17

标签: python tkinter cross-platform

我试图在一个窗口中随机显示图像,每3秒更改一次。我也希望它是跨平台的,因为我在Windows中开发,但它将在linux上运行。

目前我有这个工作代码,只需点击一下鼠标即可遍历目录的所有图像文件(下面的代码)

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

然而,这样做的方法是当鼠标点击窗口时,它会调用一个函数来关闭窗口小部件。

我遇到的问题是如何调用此功能,或关闭小部件而不用事件。有什么建议吗?

这就是我现在拥有的。这显然不起作用,因为它卡在root.mainloop()中,但它显示了我一般的想法(下面的代码)

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)

谢谢!

-Jonathan

编辑:对Bryan Oakley的回应: 我尝试了你的建议,这看起来像解决方案。

每隔3秒调用一次该函数,并且正在创建一个窗口,但图像未放置在窗口中。

我是否无法访问root用户?我如何获得访问权限?

以下是我目前的情况:

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()

谢谢!

解决方案编辑: 我没有更改代码,所以标签只创建一次,因此每次调用都会创建一个标签。我没有这样做,因为这可以应用于许多其他变量(dirlist = os.listdir(&#39;。&#39;)for exmaple),但会使代码更难阅读。除了使用更多周期之外,我没有看到任何不利之处?我没有看到记忆力随着时间的推移而增加,这对我来说非常重要。

这是代码,谢谢Bryan Oakley帮助我!!

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()

2 个答案:

答案 0 :(得分:1)

你需要删除你的无限循环 - tkinter已经有一个内置的。相反,使用after定期调用函数:

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

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

然后,在主程序中,您可以在调用mainloop之前调用该函数:

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

此外,每次都不需要changeImage创建新的标签小部件 - 在函数外部创建一次标签,并且每次调用时都只需更改图像。

答案 1 :(得分:0)

所有信用都归功于BryanOakley,以找出错误的根本原因。我稍微清理了你的代码。自从我运行Python3以来,导入也发生了一些变化,但是想确保它能够正常运行。

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()