Tk window and contents will not display

C

Chris Hare

The scenario is this:

I want to loop around all of the images in a given directory (which I know will be images, but I guess I should check), show an image in a window, wait 2 seconds and show the next one and repeat that indefinitley, which will be until the user closes the window.

This is the code I extracted from the larger program and made work - sort of - in a standalone fashion. When I run the code, each of the file names gets displayed, and I can view the images, so it has to be something I am doing wrong with this chunk of code.

However, I don't see what the problem is.

from Tkinter import *
import time
import os
import ImageTk
import Image

class externalLoopDisplay:

def show(self):
#
# Create a frame
#
self.window = Tk()
self.f = Frame(self.window, bg="Gray")
self.f.grid()
self.btnRefresh = Button(self.f, text="Close", command=self.window.destroy, bg="Gray",highlightbackground="Red", highlightcolor="Green")
self.btnRefresh.grid(row=0, column=2)
self.loopImage()

def loopImage(self):
dir = "Radar/net17"
while 1:
fileList = os.listdir(dir)
number = len(fileList)
c = 1
for gifFile in fileList:
print "externalLoopDisplay.show:","top of for loop " + str(c) + " of " + str(number)
print "externalLoopDisplay.show:","showing file " + dir + "/" + gifFile
self.window.title("Image " + str(c) + " of " + str(number))
image = Image.open(dir + "/" + gifFile)
canvasWidth, canvasHeight = image.size
self.w = Canvas(self.f, width=canvasWidth, height=canvasHeight)
photo = ImageTk.PhotoImage(image=image)
netRadarImage = Label(self.w, image=photo)
netRadarImage.image = photo
self.w.grid(row=1, column=0, columnspan=3)
netRadarImage.grid( row=1, column=0)
time.sleep(10)
c = c + 1
self.w.destroy()

loop=externalLoopDisplay()
loop.show()
 
P

Peter Otten

Chris said:
The scenario is this:

I want to loop around all of the images in a given directory (which I know
will be images, but I guess I should check), show an image in a window,
wait 2 seconds and show the next one and repeat that indefinitley, which
will be until the user closes the window.

This is the code I extracted from the larger program and made work - sort
of - in a standalone fashion. When I run the code, each of the file names
gets displayed, and I can view the images, so it has to be something I am
doing wrong with this chunk of code.

However, I don't see what the problem is.

I have not looked at your code in detail, but event loops and time.sleep()
don't play together very well. Use after(delay_in_milliseconds, callable)
instead.

Here's a simple example that loops over images passed from the command line:

import Image
import ImageTk
import os
import sys
import Tkinter as tk

from itertools import cycle

def next_image():
imagefile = next(imagefiles)
image = Image.open(imagefile)

w, h = image.size
image = image.resize((700, 700*h//w))

label.image = label["image"] = ImageTk.PhotoImage(image=image)
root.title("Now showing %s" % os.path.basename(imagefile))

root.after(2000, next_image)

if __name__ == "__main__":
imagefiles = sys.argv[1:]
assert imagefiles
imagefiles = cycle(imagefiles)

root = tk.Tk()
label = tk.Label(root)
label.pack()

root.after_idle(next_image)
root.mainloop()
 
C

Chris Hare

Chris said:
The scenario is this:

I want to loop around all of the images in a given directory (which I know
will be images, but I guess I should check), show an image in a window,
wait 2 seconds and show the next one and repeat that indefinitley, which
will be until the user closes the window.

This is the code I extracted from the larger program and made work - sort
of - in a standalone fashion. When I run the code, each of the file names
gets displayed, and I can view the images, so it has to be something I am
doing wrong with this chunk of code.

However, I don't see what the problem is.

I have not looked at your code in detail, but event loops and time.sleep()
don't play together very well. Use after(delay_in_milliseconds, callable)
instead.

Here's a simple example that loops over images passed from the command line:

import Image
import ImageTk
import os
import sys
import Tkinter as tk

from itertools import cycle

def next_image():
imagefile = next(imagefiles)
image = Image.open(imagefile)

w, h = image.size
image = image.resize((700, 700*h//w))

label.image = label["image"] = ImageTk.PhotoImage(image=image)
root.title("Now showing %s" % os.path.basename(imagefile))

root.after(2000, next_image)

if __name__ == "__main__":
imagefiles = sys.argv[1:]
assert imagefiles
imagefiles = cycle(imagefiles)

root = tk.Tk()
label = tk.Label(root)
label.pack()

root.after_idle(next_image)
root.mainloop()

Thanks Peter. I threw away what I started with and merged your code into my class:

class externalLoopDisplay:

def show(self):
main.logging.debug("externalLoopDisplay.show:","start")

self.window = Tk()

self.btnClose = Button(self.window, text="Close", command=self.window.destroy, bg=backColor,highlightbackground=warnColor, highlightcolor=okColor)
self.btnClose.grid(row=0, column=2)
self.label = Label(self.window)
self.label.grid(row=1, column=0, columnspan=3)
dirName = getRadarPath() + "/net" + str(netNumber.get()) # e.g. .../Radar/net17/net17-YYYYMMDDHHMMSS.gif
self.imagefiles = glob.glob(dirName + "/*.gif")
self.imagefiles = cycle(self.imagefiles)
self.window.after_idle(self.next_image)

def next_image(self):
imagefile = next(self.imagefiles)
image = Image.open(imagefile)

w, h = image.size
image = image.resize((600, 550*h//w))

self.label.image = self.label["image"] = ImageTk.PhotoImage(image=image) # <==== bails here
self.window.title("Now showing %s" % os.path.basename(imagefile))

self.window.after(2000, next_image)


I marked where the code bails with an error saying pyimage2 doesn't exist. All of the images exist and worked just fine with your standalone script.

Suggestions?
 
P

Peter Otten

Chris said:
Thanks Peter. I threw away what I started with and merged your code into
my class:

class externalLoopDisplay:

def show(self):
main.logging.debug("externalLoopDisplay.show:","start")

self.window = Tk()

self.btnClose = Button(self.window, text="Close",
command=self.window.destroy,
bg=backColor,highlightbackground=warnColor,
highlightcolor=okColor) self.btnClose.grid(row=0, column=2)
self.label = Label(self.window) self.label.grid(row=1, column=0,
columnspan=3)
dirName = getRadarPath() + "/net" + str(netNumber.get()) # e.g.
.../Radar/net17/net17-YYYYMMDDHHMMSS.gif
self.imagefiles = glob.glob(dirName + "/*.gif")
self.imagefiles = cycle(self.imagefiles)
self.window.after_idle(self.next_image)

def next_image(self):
imagefile = next(self.imagefiles)
image = Image.open(imagefile)

w, h = image.size
image = image.resize((600, 550*h//w))

self.label.image = self.label["image"] =
ImageTk.PhotoImage(image=image) # <==== bails here
self.window.title("Now showing %s" % os.path.basename(imagefile))

self.window.after(2000, next_image)


I marked where the code bails with an error saying pyimage2 doesn't exist.
All of the images exist and worked just fine with your standalone script.

Suggestions?

Google says you are calling Tkinter.Tk() more than once where you should
instead use Tkinter.Toplevel(). As you didn't post that part of the code
it's hard to verify, but when I add a second

root = tk.Tk()

to my example script I get a very similar exception:

Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib/python2.6/lib-tk/Tkinter.py", line 1413, in __call__
return self.func(*args)
File "/usr/lib/python2.6/lib-tk/Tkinter.py", line 498, in callit
func(*args)
File "cycle_image.py", line 16, in next_image
label.image = label["image"] = ImageTk.PhotoImage(image=image)
File "/usr/lib/python2.6/lib-tk/Tkinter.py", line 1212, in __setitem__
self.configure({key: value})
File "/usr/lib/python2.6/lib-tk/Tkinter.py", line 1205, in configure
return self._configure('configure', cnf, kw)
File "/usr/lib/python2.6/lib-tk/Tkinter.py", line 1196, in _configure
self.tk.call(_flatten((self._w, cmd)) + self._options(cnf))
TclError: image "pyimage1" doesn't exist

By the way: for future posts please remember to cut and paste the traceback,
don't paraphrase the error message.

Peter
 
C

Chris Hare

Chris said:
Thanks Peter. I threw away what I started with and merged your code into
my class:

class externalLoopDisplay:

def show(self):
main.logging.debug("externalLoopDisplay.show:","start")

self.window = Tk()

self.btnClose = Button(self.window, text="Close",
command=self.window.destroy,
bg=backColor,highlightbackground=warnColor,
highlightcolor=okColor) self.btnClose.grid(row=0, column=2)
self.label = Label(self.window) self.label.grid(row=1, column=0,
columnspan=3)
dirName = getRadarPath() + "/net" + str(netNumber.get()) # e.g.
.../Radar/net17/net17-YYYYMMDDHHMMSS.gif
self.imagefiles = glob.glob(dirName + "/*.gif")
self.imagefiles = cycle(self.imagefiles)
self.window.after_idle(self.next_image)

def next_image(self):
imagefile = next(self.imagefiles)
image = Image.open(imagefile)

w, h = image.size
image = image.resize((600, 550*h//w))

self.label.image = self.label["image"] =
ImageTk.PhotoImage(image=image) # <==== bails here
self.window.title("Now showing %s" % os.path.basename(imagefile))

self.window.after(2000, next_image)


I marked where the code bails with an error saying pyimage2 doesn't exist.
All of the images exist and worked just fine with your standalone script.

Suggestions?

Google says you are calling Tkinter.Tk() more than once where you should
instead use Tkinter.Toplevel(). As you didn't post that part of the code
it's hard to verify, but when I add a second

root = tk.Tk()

to my example script I get a very similar exception:

Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib/python2.6/lib-tk/Tkinter.py", line 1413, in __call__
return self.func(*args)
File "/usr/lib/python2.6/lib-tk/Tkinter.py", line 498, in callit
func(*args)
File "cycle_image.py", line 16, in next_image
label.image = label["image"] = ImageTk.PhotoImage(image=image)
File "/usr/lib/python2.6/lib-tk/Tkinter.py", line 1212, in __setitem__
self.configure({key: value})
File "/usr/lib/python2.6/lib-tk/Tkinter.py", line 1205, in configure
return self._configure('configure', cnf, kw)
File "/usr/lib/python2.6/lib-tk/Tkinter.py", line 1196, in _configure
self.tk.call(_flatten((self._w, cmd)) + self._options(cnf))
TclError: image "pyimage1" doesn't exist

By the way: for future posts please remember to cut and paste the traceback,
don't paraphrase the error message.

Peter

Yes - you are bang on.

Thanks. One final question if I may, how would you suggest I handle checking for new files and adding them to the list? For example, if the loop is playing and a new image is added, how can I detect it and then refresh the list of file?

I am stuck on that part with this new approach.

Chris
 
P

Peter Otten

Thanks. One final question if I may, how would you suggest I handle
checking for new files and adding them to the list? For example, if the
loop is playing and a new image is added, how can I detect it and then
refresh the list of file?

I am stuck on that part with this new approach.

Chris
Replacing

with

self.imagefiles = image_cycler(os.path.join(dirname, "*.gif"))

where image_cycler() looks as follows

def image_cycler(pattern):
while True:
for fn in glob.glob(pattern):
yield fn

would be the simplest way.

Peter
 
C

Chris Hare

with

self.imagefiles = image_cycler(os.path.join(dirname, "*.gif"))

where image_cycler() looks as follows

def image_cycler(pattern):
while True:
for fn in glob.glob(pattern):
yield fn

would be the simplest way.

Peter

Perfect!

Thank you
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top