nhsp94
Posts: 16
Joined: Fri Oct 18, 2019 2:45 pm

How do I get the slide show to stop

Mon Oct 28, 2019 8:44 pm

Hi,
I have found this code online about displaying images in a slide show. However, it does not have a feature to make it stop after all the images have been displayed.
Can anybody suggest how to go about making it stop once it displays all the images once?
When I close the window that displays the images I get the following error message:

>>> invalid command name "3029038144start"
while executing
"3029038144start"
("after" script)

Can anybody tell me what does this error mean?

I am new at coding and using raspberry pi.
The RPI model I am using is the RPI 4B 2G RAM.
The projector I am using is the Excelvan YG200

Any help will be much appreciated!
Thanks!

Here is the code:

Code: Select all

#!/usr/bin/env python3
"""Display a slideshow from a list of filenames"""

import os
import tkinter

from itertools import cycle
from PIL import Image, ImageTk


class Slideshow(tkinter.Tk):
    """Display a slideshow from a list of filenames"""
    def __init__(self, images, slide_interval):
        """Initialize
        
        images = a list of filename 
        slide_interval = milliseconds to display image
        """
        tkinter.Tk.__init__(self)
        self.geometry("+0+0")
        self.slide_interval = slide_interval
        self.images = None
        self.set_images(images)
        self.slide = tkinter.Label(self)
        self.slide.pack()

    def set_images(self, images):
         self.images = cycle(images)

    def center(self):
        """Center the slide window on the screen"""
        self.update_idletasks()
        w = self.winfo_screenwidth()
        h = self.winfo_screenheight()
        size = tuple(int(_) for _ in self.geometry().split('+')[0].split('x'))
        x = w / 2 - size[0] / 2
        y = h / 2 - size[1] / 2
        self.geometry("+%d+%d" % (x, y))

    def set_image(self):
        """Setup image to be displayed"""
        self.image_name = next(self.images)
        filename, ext = os.path.splitext(self.image_name)
        self.image = ImageTk.PhotoImage(Image.open(self.image_name))
        
    def main(self):
        """Display the images"""
        self.set_image()
        self.slide.config(image=self.image)
        self.title(self.image_name)
        self.center()
        self.after(self.slide_interval, self.start)
    
    def start(self):
        """Start method"""
        self.main()
        self.mainloop()


if __name__ == "__main__":
    slide_interval = 2500
    
    # use a list
    #images = ["image1.jpg",
              #"image2.jpeg",
              #"/home/pi/image3.gif",
              #"/home/pi/images/image4.png",
              #"images/image5.bmp"]
    
    # all the specified file types in a directory 
    # "." us the directory the script is in.
    # exts is the file extentions to use.  it can be any extention that pillow supports
    # http://pillow.readthedocs.io/en/3.3.x/handbook/image-file-formats.html
    import glob
    images = glob.glob("*.jpg")
    path = "."
    exts = ["jpg", "bmp", "png", "gif", "jpeg"]
    images = [fn for fn in os.listdir(path) if any(fn.endswith(ext) for ext in exts)]

    # start the slideshow
    slideshow = Slideshow(images, slide_interval)
    slideshow.start()

fruitoftheloom
Posts: 25320
Joined: Tue Mar 25, 2014 12:40 pm
Location: Delightful Dorset

Re: How do I get the slide show to stop

Tue Oct 29, 2019 6:45 pm

nhsp94 wrote:
Mon Oct 28, 2019 8:44 pm
Hi,
I have found this code online about displaying images in a slide show. However, it does not have a feature to make it stop after all the images have been displayed.
Can anybody suggest how to go about making it stop once it displays all the images once?
When I close the window that displays the images I get the following error message:

>>> invalid command name "3029038144start"
while executing
"3029038144start"
("after" script)

Can anybody tell me what does this error mean?

I am new at coding and using raspberry pi.
The RPI model I am using is the RPI 4B 2G RAM.
The projector I am using is the Excelvan YG200

Any help will be much appreciated!
Thanks!

Here is the code:

Code: Select all

#!/usr/bin/env python3
"""Display a slideshow from a list of filenames"""

import os
import tkinter

from itertools import cycle
from PIL import Image, ImageTk


class Slideshow(tkinter.Tk):
    """Display a slideshow from a list of filenames"""
    def __init__(self, images, slide_interval):
        """Initialize
        
        images = a list of filename 
        slide_interval = milliseconds to display image
        """
        tkinter.Tk.__init__(self)
        self.geometry("+0+0")
        self.slide_interval = slide_interval
        self.images = None
        self.set_images(images)
        self.slide = tkinter.Label(self)
        self.slide.pack()

    def set_images(self, images):
         self.images = cycle(images)

    def center(self):
        """Center the slide window on the screen"""
        self.update_idletasks()
        w = self.winfo_screenwidth()
        h = self.winfo_screenheight()
        size = tuple(int(_) for _ in self.geometry().split('+')[0].split('x'))
        x = w / 2 - size[0] / 2
        y = h / 2 - size[1] / 2
        self.geometry("+%d+%d" % (x, y))

    def set_image(self):
        """Setup image to be displayed"""
        self.image_name = next(self.images)
        filename, ext = os.path.splitext(self.image_name)
        self.image = ImageTk.PhotoImage(Image.open(self.image_name))
        
    def main(self):
        """Display the images"""
        self.set_image()
        self.slide.config(image=self.image)
        self.title(self.image_name)
        self.center()
        self.after(self.slide_interval, self.start)
    
    def start(self):
        """Start method"""
        self.main()
        self.mainloop()


if __name__ == "__main__":
    slide_interval = 2500
    
    # use a list
    #images = ["image1.jpg",
              #"image2.jpeg",
              #"/home/pi/image3.gif",
              #"/home/pi/images/image4.png",
              #"images/image5.bmp"]
    
    # all the specified file types in a directory 
    # "." us the directory the script is in.
    # exts is the file extentions to use.  it can be any extention that pillow supports
    # http://pillow.readthedocs.io/en/3.3.x/handbook/image-file-formats.html
    import glob
    images = glob.glob("*.jpg")
    path = "."
    exts = ["jpg", "bmp", "png", "gif", "jpeg"]
    images = [fn for fn in os.listdir(path) if any(fn.endswith(ext) for ext in exts)]

    # start the slideshow
    slideshow = Slideshow(images, slide_interval)
    slideshow.start()

Is this related to your other posts ??
The information is out there....you just have to let it in.

My other Linux machine is a ChromeBox

nhsp94
Posts: 16
Joined: Fri Oct 18, 2019 2:45 pm

Re: How do I get the slide show to stop

Tue Oct 29, 2019 7:41 pm

fruitoftheloom wrote:
Tue Oct 29, 2019 6:45 pm
nhsp94 wrote:
Mon Oct 28, 2019 8:44 pm
Hi,
I have found this code online about displaying images in a slide show. However, it does not have a feature to make it stop after all the images have been displayed.
Can anybody suggest how to go about making it stop once it displays all the images once?
When I close the window that displays the images I get the following error message:

>>> invalid command name "3029038144start"
while executing
"3029038144start"
("after" script)

Can anybody tell me what does this error mean?

I am new at coding and using raspberry pi.
The RPI model I am using is the RPI 4B 2G RAM.
The projector I am using is the Excelvan YG200

Any help will be much appreciated!
Thanks!

Here is the code:

Code: Select all

#!/usr/bin/env python3
"""Display a slideshow from a list of filenames"""

import os
import tkinter

from itertools import cycle
from PIL import Image, ImageTk


class Slideshow(tkinter.Tk):
    """Display a slideshow from a list of filenames"""
    def __init__(self, images, slide_interval):
        """Initialize
        
        images = a list of filename 
        slide_interval = milliseconds to display image
        """
        tkinter.Tk.__init__(self)
        self.geometry("+0+0")
        self.slide_interval = slide_interval
        self.images = None
        self.set_images(images)
        self.slide = tkinter.Label(self)
        self.slide.pack()

    def set_images(self, images):
         self.images = cycle(images)

    def center(self):
        """Center the slide window on the screen"""
        self.update_idletasks()
        w = self.winfo_screenwidth()
        h = self.winfo_screenheight()
        size = tuple(int(_) for _ in self.geometry().split('+')[0].split('x'))
        x = w / 2 - size[0] / 2
        y = h / 2 - size[1] / 2
        self.geometry("+%d+%d" % (x, y))

    def set_image(self):
        """Setup image to be displayed"""
        self.image_name = next(self.images)
        filename, ext = os.path.splitext(self.image_name)
        self.image = ImageTk.PhotoImage(Image.open(self.image_name))
        
    def main(self):
        """Display the images"""
        self.set_image()
        self.slide.config(image=self.image)
        self.title(self.image_name)
        self.center()
        self.after(self.slide_interval, self.start)
    
    def start(self):
        """Start method"""
        self.main()
        self.mainloop()


if __name__ == "__main__":
    slide_interval = 2500
    
    # use a list
    #images = ["image1.jpg",
              #"image2.jpeg",
              #"/home/pi/image3.gif",
              #"/home/pi/images/image4.png",
              #"images/image5.bmp"]
    
    # all the specified file types in a directory 
    # "." us the directory the script is in.
    # exts is the file extentions to use.  it can be any extention that pillow supports
    # http://pillow.readthedocs.io/en/3.3.x/handbook/image-file-formats.html
    import glob
    images = glob.glob("*.jpg")
    path = "."
    exts = ["jpg", "bmp", "png", "gif", "jpeg"]
    images = [fn for fn in os.listdir(path) if any(fn.endswith(ext) for ext in exts)]

    # start the slideshow
    slideshow = Slideshow(images, slide_interval)
    slideshow.start()

Is this related to your other posts ??
Hello,
Yes. This is also part of what I have to do about displaying images. I posted this message in the Python forum because another user here suggested it would be better to do so.
My apologies if I did something wrong. I am new to the forums.
Thank you for your prompt reply!

billio
Posts: 71
Joined: Thu Dec 15, 2011 8:25 am
Contact: Website

Re: How do I get the slide show to stop

Tue Oct 29, 2019 9:39 pm

The reason this slideshow keeps returning to the begining over and over again is because it uses the cycle function from the itertools module. The purpose of this function is to create an iterator that cycles through a list over and over again.

Code: Select all

from itertools import cycle
...
    self.set_images(self,images) :
         self.images = cycle(images) # sets up an infinite iterator 
If you changed the cycle(images) to iter(images) the display will go through the images just once. When it reaches the end of the list the final image remains in the window and there is a StopIteration error. If you want a tidier ending to the display you need to trap this error and add some extra code.

User avatar
joelostinspace
Posts: 108
Joined: Sat Aug 10, 2019 2:51 pm
Location: Earth

Re: How do I get the slide show to stop

Tue Oct 29, 2019 11:06 pm

When I run you program in idle and close the window I don't get an error. I also ran it in the terminal and no error.
you can always create a button in a toplevel dialog and kill the script that way too.
Modified your script to read a directory make a list and scroll through the images.
The script is in a folder - home/pi/SlideShow/tk_slideshow.py
my image directory is in home/pi/png
added a pause and unpause to halt the loop

Code: Select all

#!/usr/bin/env python3
"""Display a slideshow from a list of filenames"""

import os
import tkinter
from itertools import cycle
from PIL import Image, ImageTk


class Slideshow(tkinter.Tk):
    """Display a slideshow from a list of filenames"""
    def __init__(self, images, slide_interval):
        """Initialize
        
        images = a list of filename 
        slide_interval = milliseconds to display image
        """
        tkinter.Tk.__init__(self)
        self.geometry("+0+0")
        self.slide_interval = slide_interval
        self.images = cycle(images)        
        self.slide = tkinter.Label(self)
        self.slide.pack()
        self.quit_slideShow()
        self.main()
        tkinter.mainloop()
    def quit_slideShow(self):
        q_dialog= tkinter.Toplevel(width=200,height=200,bg='red')
        q_dialog.title('quit')
        q_dialog.protocol('WM_DELETE_WINDOW', lambda: None)
        btn= tkinter.Button(q_dialog, text='Exit',
                            command= lambda: tkinter.Tk.destroy(self))
        btn.place(x=100,y=100)
        self.btn2= tkinter.Button(q_dialog, text='Pause', command= self.on_pause)
        self.btn2.place(x=50, y=50)
        self.btn3= tkinter.Button(q_dialog, text='restart',
                                  command= self.on_restart, state='disabled')
        self.btn3.place(x=16, y=15)
    def on_restart(self):
        self.btn3.config(state='disabled')
        self.btn2.config(state='normal')
        self.main()
    def on_pause(self):
        self.slide.after_cancel(self.loop)
        self.btn3.config(state= 'normal')
        self.btn2.config(state= 'disabled')

    def center(self):
        """Center the slide window on the screen"""
        self.update_idletasks()
        w = self.winfo_screenwidth()
        h = self.winfo_screenheight()
        size = tuple(int(_) for _ in self.geometry().split('+')[0].split('x'))
        x = w / 2 - size[0] / 2
        y = h / 2 - size[1] / 2
        self.geometry("+%d+%d" % (x, y))

    def set_image(self):
        """Setup image to be displayed"""
        self.image_name = next(self.images)        
        file= os.path.join(path, self.image_name)
        self.image = ImageTk.PhotoImage(Image.open(file))
        
    def main(self):
        """Display the images"""
        self.set_image()
        self.slide.config(image=self.image)
        self.title(self.image_name)
        self.center()
        # start recursion
        self.loop= self.slide.after(self.slide_interval, self.main)   
    


if __name__ == "__main__":
    slide_interval = 2500
    
    # use a list
    #images = ["image1.jpg",
              #"image2.jpeg",
              #"/home/pi/image3.gif",
              #"/home/pi/images/image4.png",
              #"images/image5.bmp"]
    
    # all the specified file types in a directory 
    # "." us the directory the script is in.
    # exts is the file extentions to use.  it can be any extention that pillow supports
    # http://pillow.readthedocs.io/en/3.3.x/handbook/image-file-formats.html
    
    path = "../png"
    exts = ["jpg", "bmp", "png", "gif", "jpeg"]
    images = [fn for fn in os.listdir(path) if any(fn.endswith(ext) for ext in exts)]

    # start the slideshow
    slideshow = Slideshow(images, slide_interval)
    


To travel is to discover that everyone is wrong about other countries.


--- Aldous Huxley

nhsp94
Posts: 16
Joined: Fri Oct 18, 2019 2:45 pm

Re: How do I get the slide show to stop

Tue Oct 29, 2019 11:27 pm

billio wrote:
Tue Oct 29, 2019 9:39 pm
The reason this slideshow keeps returning to the begining over and over again is because it uses the cycle function from the itertools module. The purpose of this function is to create an iterator that cycles through a list over and over again.

Code: Select all

from itertools import cycle
...
    self.set_images(self,images) :
         self.images = cycle(images) # sets up an infinite iterator 
If you changed the cycle(images) to iter(images) the display will go through the images just once. When it reaches the end of the list the final image remains in the window and there is a StopIteration error. If you want a tidier ending to the display you need to trap this error and add some extra code.
Hello,
Thank you so much for your help! I will implement your advice and report back with the results.
Also, do you have any suggestions of how to display one image through a projector and a different one to a monitor. I am working on a code that mimics how vision works, e.g. inside the human eye the image is upside down, but what we see through the eye is not (Am I making sense?)
I apologize if that statement sounded confusing. Any help will be much appreciated.
Last edited by nhsp94 on Wed Oct 30, 2019 1:31 am, edited 1 time in total.

nhsp94
Posts: 16
Joined: Fri Oct 18, 2019 2:45 pm

Re: How do I get the slide show to stop

Wed Oct 30, 2019 1:22 am

joelostinspace wrote:
Tue Oct 29, 2019 11:06 pm
When I run you program in idle and close the window I don't get an error. I also ran it in the terminal and no error.
you can always create a button in a toplevel dialog and kill the script that way too.
Modified your script to read a directory make a list and scroll through the images.
The script is in a folder - home/pi/SlideShow/tk_slideshow.py
my image directory is in home/pi/png
added a pause and unpause to halt the loop

Code: Select all

#!/usr/bin/env python3
"""Display a slideshow from a list of filenames"""

import os
import tkinter
from itertools import cycle
from PIL import Image, ImageTk


class Slideshow(tkinter.Tk):
    """Display a slideshow from a list of filenames"""
    def __init__(self, images, slide_interval):
        """Initialize
        
        images = a list of filename 
        slide_interval = milliseconds to display image
        """
        tkinter.Tk.__init__(self)
        self.geometry("+0+0")
        self.slide_interval = slide_interval
        self.images = cycle(images)        
        self.slide = tkinter.Label(self)
        self.slide.pack()
        self.quit_slideShow()
        self.main()
        tkinter.mainloop()
    def quit_slideShow(self):
        q_dialog= tkinter.Toplevel(width=200,height=200,bg='red')
        q_dialog.title('quit')
        q_dialog.protocol('WM_DELETE_WINDOW', lambda: None)
        btn= tkinter.Button(q_dialog, text='Exit',
                            command= lambda: tkinter.Tk.destroy(self))
        btn.place(x=100,y=100)
        self.btn2= tkinter.Button(q_dialog, text='Pause', command= self.on_pause)
        self.btn2.place(x=50, y=50)
        self.btn3= tkinter.Button(q_dialog, text='restart',
                                  command= self.on_restart, state='disabled')
        self.btn3.place(x=16, y=15)
    def on_restart(self):
        self.btn3.config(state='disabled')
        self.btn2.config(state='normal')
        self.main()
    def on_pause(self):
        self.slide.after_cancel(self.loop)
        self.btn3.config(state= 'normal')
        self.btn2.config(state= 'disabled')

    def center(self):
        """Center the slide window on the screen"""
        self.update_idletasks()
        w = self.winfo_screenwidth()
        h = self.winfo_screenheight()
        size = tuple(int(_) for _ in self.geometry().split('+')[0].split('x'))
        x = w / 2 - size[0] / 2
        y = h / 2 - size[1] / 2
        self.geometry("+%d+%d" % (x, y))

    def set_image(self):
        """Setup image to be displayed"""
        self.image_name = next(self.images)        
        file= os.path.join(path, self.image_name)
        self.image = ImageTk.PhotoImage(Image.open(file))
        
    def main(self):
        """Display the images"""
        self.set_image()
        self.slide.config(image=self.image)
        self.title(self.image_name)
        self.center()
        # start recursion
        self.loop= self.slide.after(self.slide_interval, self.main)   
    


if __name__ == "__main__":
    slide_interval = 2500
    
    # use a list
    #images = ["image1.jpg",
              #"image2.jpeg",
              #"/home/pi/image3.gif",
              #"/home/pi/images/image4.png",
              #"images/image5.bmp"]
    
    # all the specified file types in a directory 
    # "." us the directory the script is in.
    # exts is the file extentions to use.  it can be any extention that pillow supports
    # http://pillow.readthedocs.io/en/3.3.x/handbook/image-file-formats.html
    
    path = "../png"
    exts = ["jpg", "bmp", "png", "gif", "jpeg"]
    images = [fn for fn in os.listdir(path) if any(fn.endswith(ext) for ext in exts)]

    # start the slideshow
    slideshow = Slideshow(images, slide_interval)
    

Hi,
Thank you for you advice! Your buttons idea sounds great, but the program I am working on requires the code to stop the slide show without any user interaction (e.g. any press of a button).
Thank you so much for taking the time to look into my post!

nhsp94
Posts: 16
Joined: Fri Oct 18, 2019 2:45 pm

Re: How do I get the slide show to stop

Mon Nov 04, 2019 3:19 am

Hello,
I am now working on displaying one image as opposed to a slide show. I have created a script (Python 3) to display an image, but when I run
the program it tells me the following error
return getattr(self.tk, attr)
AttributeError:'_tkinter.tkapp' object has no attribute 'showImg'

Can somebody explain it to me please and give me suggestions on how to proceed to get the code to display an image?
I am new to Python 3 and raspberry pi. I am learning this on my own to complete a school assignment. Thank you for your patience!
Thanks in advance for any help you can provide!
Here is my code:

import tkinter as tk
from PIL import Image, ImageTk

LARGE_FONT= ("Times New Roman", 12)

class Demoapp(tk.Tk):

def __init__(self, *args, **kwargs):

tk.Tk.__init__(self, *args, **kwargs)
container = tk.Frame(self)

container.pack(side="top", fill="both", expand = True)

container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)

self.frames = {}

frame = StartPage(container, self)

self.frames[StartPage] = frame

frame.grid(row=0, column = 0, sticky="nsew")

self.show_frame(StartPage)

def show_frame(self, cont):

frame = self.frames[cont]
frame.tkraise()

def showImg(self):
load=Image.open('image.png')
render=ImageTk.PhotoImage(load)

class StartPage(tk.Frame):

def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Start Page", font=LARGE_FONT)
label.pack(pady=10, padx=10)

button1 = tk.Button(self, text="Display Image",
command=lambda: showImg('image.png'))
button1.pack()

app= Demoapp()
app.mainloop()

Return to “Python”