Home > Software design >  python tkinter goes not responing
python tkinter goes not responing

Time:06-11

I just made a simple project with Tkinter GUI, but when I launch it and enter username, its window stops responding 'til the requests and instaloader processes are done, then it will be ok. Can I make a 'please wait' thing to avoid not responding? or does it get better if I migrate to another GUI?

from tkinter import *
import instaloader
from PIL import ImageTk, Image
import requests
from io import BytesIO


def insta(username):
    L = instaloader.Instaloader()
    profile = instaloader.Profile.from_username(L.context, username)

    label2.config(text=profile.full_name)
    label3.config(text=profile.biography)
    url=profile.get_profile_pic_url()
    response = requests.get(url)
    img_data = response.content
    img = ImageTk.PhotoImage(Image.open(BytesIO(img_data)))
    panel = Label(image=img)
    panel.place(x=150,y=100)
    label4.config(text="Done")
    


window = Tk()
window.geometry("600x600")
window.maxsize(600, 600)
window.minsize(600, 600)
window.title("Instagram Profile Downloader")

# label
label = Label(window, text="Enter UserName to Download Profile Image:",
              fg="black", bg="#f4b265")
label.place(x=180, y=20)
label2 = Label(window, text="")
label2.place(x=100, y=70)
label3 = Label(window, text="")
label3.place(x=100, y=100)
label4 = Label(window, text="", fg="red")
label4.place(x=380, y=50)


# button
def butt():
    if input.get() == "":
        label4.config(text="Please Enter Username")
        return
    else:
        insta(input.get())


button = Button(window, text="Download", fg="white",
                bg="#095e95", command=butt)
button.place(x=310, y=47)

# input
input = Entry(window)
input.place(x=180, y=50)

window.mainloop()

CodePudding user response:

Tkinter stuff is running in the main thread and so when you call something in the main thread that takes time the GUI will be blocked while that function is running. To solve this you need to use threads to make sure the call to insta is running separate from the main thread where tkinter is running but also need to make sure that you dont call tkinter functions on that other thread because tkinter only works in the main thread. Here's an exemple of how you could acheive it:

import threading


class InstaThread:
    def __init__(self, username):
        self.profile = None
        self.img_data = None
        
        # Disable the button while instaloader is running
        button["text"] = "Loading..."
        button["state"] = DISABLED

        self.thread = threading.Thread(target=self.insta, args=(username,))
        self.thread.start()
        
        self.check_thread()

    
    # Check periodically if the function has alread run
    def check_thread(self):
        if self.thread.is_alive():
            window.after(100, self.check_thread)
        else:
            label2.config(text=self.profile.full_name)
            label3.config(text=self.profile.biography)
            panel = Label(window)

            img = ImageTk.PhotoImage(Image.open(BytesIO(self.img_data)))
            # Also updated this so that the image would really show in the panel
            panel.image = img
            panel.config(image = img)
            
            panel.place(x=150,y=100)
            label4.config(text="Done")
            # Reset button 
            button["text"] = "Download"
            button["state"] = NORMAL
    
    # Function that will be running in other thread and updating the profile and img_data varibles of this class
    def insta(self, username):
        L = instaloader.Instaloader()
        self.profile = instaloader.Profile.from_username(L.context, username)
        url=self.profile.get_profile_pic_url()
        response = requests.get(url)
        self.img_data = response.content

Now in the Butt function you just need to call InstaThread(input.get()) instead of insta(input.get()) and like this when you click the button it will disable and say Loading while the function is running and the rest of the GUI will continue working fine

Another suggestion I have is for you to make a class for your GUI so that you have it all in one place and can access it anywhere inside the class so that you dont have to be having global variables for buttons and labels.

  • Related