top of page

Building a Simple Image Viewer with Tkinter and Pillow in

Author: Afreen


Introduction:


In the realm of graphical user interfaces (GUI), 's Tkinter library provides a versatile toolkit for creating interactive applications. When combined with the powerful image processing capabilities of the Pillow library, you can easily develop a simple yet effective image viewer. In this article, we will explore a script that utilizes Tkinter and Pillow to create an interactive image viewer with navigation buttons and a slideshow feature.


The highlighted portions contain the codes and corresponding explanations either above or below them.


To code along with the project, you can go to the following GitHub repository link: https://github.com/AfreenInnovates/image-slider


Setting Up the Environment:


Before diving into the code, ensure you have Tkinter and Pillow installed in your environment. You can install them using the following commands:


pip install tk

pip install Pillow



Understanding the Code:


Now, let's break down the code step by step:


1. Importing Libraries:


The script begins by importing the necessary libraries:


from tkinter import *

from PIL import ImageTk, Image

Tkinter is employed for creating the graphical user interface, while Pillow handles the loading and processing of images.




2. Creating the Tkinter Window:

root = Tk()

# Any name can be used instead of root.


This line initializes the main Tkinter window, serving as the container for the graphical elements.





3. Loading and Storing Images:


The script loads a set of images and stores them in a list:


my_img_1 = ImageTk.PhotoImage(Image.open("images/d1.jpg"))

my_img_2 = ImageTk.PhotoImage(Image.open("images/d2.jpg"))


# ... Repeat for other images. Here, d1.jpg and so on are images in the folder “images”. If you just want to access one image, then just type: my_img_1 = ImageTk.PhotoImage(Image.open("d1.jpg"))

# Check the repo link to understand.


# Storing all images in a list (same as array).

my_images = [my_img_1, my_img_2, my_img_3, my_img_4, my_img_5]


# The images are converted into Tkinter PhotoImage objects and organized into a list named `my_images`.




4. Displaying the first image:

my_label_1 = Label(root, image=my_img_1)

my_label_1.grid(row=0, column=0, columnspan=3)

# This code creates a Tkinter Label widget (`my_label_1`) to display the first image. The label is positioned on the grid in the first row, spanning three columns.




6. Functions for handling buttons:


def btn_forw():

global img_num

# If the current image is the first, disable the previous button

if img_num == 1:

prev_btn.config(state=DISABLED)

# Increment the image number

img_num += 1

# Check if we have reached the end of the image list

if img_num > len(my_images):

img_num = 1 # Wrap around to the first image

# Update the display

update_display()

# Enable or disable navigation buttons based on the current image number

prev_btn.config(state=NORMAL if img_num > 1 else DISABLED)

forw_btn.config(state=NORMAL if img_num < len(my_images) else DISABLED)


The function uses the global keyword to access and modify the global variable img_num.

It first checks if the current image is the first one. If so, it disables the previous button (prev_btn) since there's no previous image.

The image number is then incremented, and the function checks if it has reached the end of the image list. If so, it wraps around to the first image for a continuous loop.

The update_display() function is called to refresh the displayed image.

Finally, the state of the previous and forward buttons is adjusted based on the current image number to enable or disable them accordingly.



def btn_prev():

global img_num

# If the current image is the last, disable the forward button

if img_num == len(my_images):

forw_btn.config(state=DISABLED)

# Decrement the image number

img_num -= 1

# Check if we have reached the start of the image list

if img_num < 1:

img_num = len(my_images) # Set to the last image

# Update the display

update_display()

# Enable or disable navigation buttons based on the current image number

prev_btn.config(state=NORMAL if img_num > 1 else DISABLED)

forw_btn.config(state=NORMAL if img_num < len(my_images) else DISABLED)


Similar to btn_forw(), this function uses the global keyword to access and modify the global variable img_num.

It checks if the current image is the last one. If so, it disables the forward button (forw_btn) since there's no next image.

The image number is decremented, and the function checks if it has reached the start of the image list. If so, it sets the image number to the last image for a continuous loop.

The update_display() function is called to refresh the displayed image.

Finally, the state of the previous and forward buttons is adjusted based on the current image number to enable or disable them accordingly.



def update_display():

my_label_1.configure(image=my_images[img_num - 1])

img_num_label.config(text=f"Image {img_num}/{len(my_images)}")


my_label_1 is updated with the image from my_images at the current index (img_num - 1).

The text of img_num_label is updated to reflect the current image number out of the total number of images.



7. Navigation Buttons:


prev_btn = Button(root, text="<<", command=btn_prev, state=DISABLED)

exit_btn = Button(root, text="Exit app", command=root.quit)

forw_btn = Button(root, text=">>", command=btn_forw)

# Three buttons are created for navigation – moving backward, quitting the application, and moving forward through the images.




8. Grid Placement for Buttons:


prev_btn.grid(row=1, column=0)

exit_btn.grid(row=1, column=1)

forw_btn.grid(row=1, column=2)


# The navigation buttons are positioned on the grid in the second row.


9. Image Counter Label:


img_num_label = Label(root, text=f"Image {img_num}/{len(my_images)}")

img_num_label.grid(row=2, column=0, columnspan=3)

# A label (`img_num_label`) is created to display the current image number out of the total number of images. It is placed in the third row, spanning three columns.




10. Slideshow Feature:

def start_slideshow():

btn_forw() # Starts slideshow from the current image

root.after(1000, start_slideshow) # Change image every 1000 milliseconds (1 second)


start_slideshow_btn = Button(root, text="Start Slideshow", command=start_slideshow)

start_slideshow_btn.grid(row=3, column=0, columnspan=3)

# The script defines a function `start_slideshow` that automatically advances to the next image at regular intervals. The function is triggered by the "Start Slideshow" button.




11. Main Event Loop:


root.mainloop()

# This line initiates the main event loop of the Tkinter application, ensuring the graphical user interface remains responsive.




Congratulations on creating an amazing project! Keep progressing and create even more :)


98 views0 comments
bottom of page