GUI overloading in Python

Question:

I am currently developing a GUI in Python and have stuck on a function that is supposed to show wipe animation of Image A covering Image B in square frame. When I run the program, GUI freezes and doesn’t respond.

def apply_transitions():
    ImageA_Width, ImageA_Height = img.size
    data_A_norm = asarray(img2)
    data_B_norm = asarray(img)

    def get_frame(frame_number):
        frame = np.zeros((ImageA_Height, ImageA_Width, 3))
        for x in range(0, ImageA_Width):
            for y in range(0, ImageA_Height):
                if x < frame_number: 
                    frame[x,y] = data_A_norm[x,y]
                else:
                    frame[x,y] = data_B_norm[x,y]
        return frame
    
    for frame_number in range(ImageA_Width):
        frame = get_frame(frame_number)
        image_opened = Image.fromarray((frame*255).astype(np.uint8))
        shot = ImageTk.PhotoImage(image_opened)
        label = Label(window, image=shot)
        label.pack()
        label.place(x=800, y=200)
        time.sleep(0.1)

I can assume the problem is related to the infinite loops, but I can’t figure out what exactly doesn’t let this loop end.

Asked By: Pytho

||

Answers:

Whilst it may not be the sole cause of your program freezing, "time.sleep()" stops the program from processing data which extends to the GUI, meaning while the sleep is active, the GUI will not respond to any event that happens to it. I’ve found that when running GUI programs on windows (not sure about other os’s), the system decides that while it is sleeping it must have crashed, so will sometimes tell you that the application is not responding. You should probably try another way to get your program to pause other than sleep (for instance, pygames clock)
🙂

Answered By: G7itch

It looks like the problem is that the for loop in the apply_transitions function never ends, because it doesn’t have a terminating condition. This causes the GUI to freeze because the function is never returning control to the main event loop.

One way to fix this problem is to use the after method of the Tkinter Label widget to schedule the next frame to be displayed after a certain amount of time has passed. This allows the main event loop to continue running and the GUI to remain responsive.

Here is an example of how you can modify the apply_transitions function to use the after method:

def apply_transitions():
    ImageA_Width, ImageA_Height = img.size
    data_A_norm = asarray(img2)
    data_B_norm = asarray(img)

    def get_frame(frame_number):
        frame = np.zeros((ImageA_Height, ImageA_Width, 3))
        for x in range(0, ImageA_Width):
            for y in range(0, ImageA_Height):
                if x < frame_number: 
                    frame[x,y] = data_A_norm[x,y]
                else:
                    frame[x,y] = data_B_norm[x,y]
        return frame
    
    def show_frame(frame_number):
        if frame_number < ImageA_Width:
            frame = get_frame(frame_number)
            image_opened = Image.fromarray((frame*255).astype(np.uint8))
            shot = ImageTk.PhotoImage(image_opened)
            label = Label(window, image=shot)
            label.pack()
            label.place(x=800, y=200)
            label.after(100, show_frame, frame_number+1)
    
    show_frame(0)

In this version of the function, the show_frame function is called with the initial frame number of 0. It displays the frame and then schedules the next frame to be displayed using the after method, passing the next frame number as an argument. This process continues until the final frame is displayed, at which point the function returns and the animation is complete.

I hope this helps! Let me know if you have any questions or if there’s anything else I can do to help.

Answered By: kamdim
Categories: questions Tags: , , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.