Tuesday, January 4, 2022

[SOLVED] Tkinter image application keeps freezing system after it runs

Issue

I'm testing an app with the following code:

#!/usr/bin/env python3
import os
from tkinter import *
from tkinter import filedialog
from PIL import Image, ImageTk

root = Tk()
root.title("Image Viewer App")
root.withdraw()
location_path = filedialog.askdirectory()
root.resizable(0, 0)

#Load files in directory path
im=[]
def load_images(loc_path):
    for path,dirs,filenames in os.walk(loc_path):
        for filename in filenames:
            im.append(ImageTk.PhotoImage(Image.open(os.path.join(path, filename))))

load_images(location_path)
root.geometry("700x700")
#Display test image with Label
label=Label(root, image=im[0])
label.pack()
root.mainloop()

The problem is that when I run it, my system will freeze and Linux distro will crash. I'm not able to tell what I'm doing wrong except I'm not sure if it's a good idea to store an entire image within a list variable vs just storing the location itself. Right now, it's just testing the ability to open one image with img=[0].


Solution

The loading of images may take time and cause the freeze. Better to run load_images() in a child thread instead:

import os
import threading
import tkinter as tk
from tkinter import filedialog
from PIL import Image, ImageTk

root = tk.Tk()
root.geometry("700x700")
root.title("Image Viewer App")
root.resizable(0, 0)
root.withdraw()

#Display test image with Label
label = tk.Label(root)
label.pack()

location_path = filedialog.askdirectory()
root.deiconify()  # show the root window

#Load files in directory path
im = []
def load_images(loc_path):
    for path, dirs, filenames in os.walk(loc_path):
        for filename in filenames:
            im.append(ImageTk.PhotoImage(file=os.path.join(path, filename)))
    print(f'Total {len(im)} images loaded')

if location_path:
    # run load_images() in a child thread
    threading.Thread(target=load_images, args=[location_path]).start()

    # show first image
    def show_first_image():
        label.config(image=im[0]) if len(im) > 0 else label.after(50, show_first_image)

    show_first_image()

root.mainloop()

Note that I have changed from tkinter import * to import tkinter as tk as wildcard import is not recommended.



Answered By - acw1668