pythontkinter

Tkinter window shows “Not Responding” while running my text-to-speech code (how do I prevent the GUI from freezing?)


I’m making a GUI application in Python using Tkinter that reads text out loud from PDF, DOCX, TXT, and images using gTTS.

The program works, but sometimes Tkinter window becomes unresponsive and shows “Not Responding” while the text-to-speech is running.

Here is the minimal code that reproduces the issue:

from gtts import gTTS
import tkinter as tk
from tkinter import *
from tkinter import filedialog
from tkinter import PhotoImage
import pyaudio
import os
from playsound import playsound


parent = tk.Tk()
parent.title("Title Screen")
image = PhotoImage(file=r"C:\Users\aksha\Downloads\Techlogo.png")
label = Label(parent, image=image)
label.pack()
label.image = image
parent.update()


def speak(words):
    tts = gTTS(text=words, lang="en")
    tts.save("output.mp3")
    playsound("output.mp3")
    os.remove("output.mp3")


intro = (
    "...Hi this is a software to help you read text out loud.. please select a file.."
)
speak(intro)


name = filedialog.askopenfilename(
    initialdir=r"C:\\",
    filetypes=(
        ("PDF files", "*.pdf"),
        ("Word files", "*.docx"),
        ("Text files", "*.txt"),
        ("Image files", "*.jpg *.jpeg *.png"),
    ),
)


if name.endswith(".txt"):
    with open(name, "r") as file:
        x = file.read()
        speak(x)
else:

    x = "please try again"
    speak(x)


speak("Task complete. You may close the window.")

parent.mainloop()

Solution

  • DISCLAIMER: I did not test this code before running it, and I don't know how well tkinter plays with asynchronous functions. This answer also assumes that @TheLizzard is correct in thinking that playsound blocks the main thread

    When I want to run something on a different thread, I typically use asyncio.to_thread(). For example, you could run playsound in a different thread, then that should fix the 'Not Responding' dialog. Here is what your code would look like:

    # Source - https://stackoverflow.com/q/79839637
    # Posted by Akshadha Awasthi, modified by community. See post 'Timeline' for change history
    # Retrieved 2025-12-06, License - CC BY-SA 4.0
    
    from gtts import gTTS
    import tkinter as tk
    from tkinter import *
    from tkinter import filedialog
    from tkinter import PhotoImage
    import pyaudio
    import os
    from playsound import playsound
    
    import asyncio
    
    parent = tk.Tk()
    parent.title("Title Screen")
    image = PhotoImage(file=r"C:\Users\aksha\Downloads\Techlogo.png")
    label = Label(parent, image=image)
    label.pack()
    label.image = image
    parent.update()
    
    
    async def speak(words):
        tts = gTTS(text=words, lang="en")
        tts.save("output.mp3")
    
        await asyncio.to_thread(playsound, "output.mp3") # Use asyncio.th_thread to run playsound in a different thread, making it so playsound doesn't block the main thread anymore
        os.remove("output.mp3")
    
    
    intro = (
        "...Hi this is a software to help you read text out loud.. please select a file.."
    )
    speak(intro)
    
    
    name = filedialog.askopenfilename(
        initialdir=r"C:\\",
        filetypes=(
            ("PDF files", "*.pdf"),
            ("Word files", "*.docx"),
            ("Text files", "*.txt"),
            ("Image files", "*.jpg *.jpeg *.png"),
        ),
    )
    
    
    if name.endswith(".txt"):
        with open(name, "r") as file:
            x = file.read()
            asyncio.run(speak(x)) # Use asyncio.run to run speak so you don't get warning about a co routine not being awaited
    else:
    
        x = "please try again"
        asyncio.run(speak(x)) # Use asyncio.run to run speak so you don't get warning about a co routine not being awaited
    
    
    asyncio.run(speak("Task complete. You may close the window.")) # Use asyncio.run to run speak so you don't get warning about a co routine not being awaited
    parent.mainloop()
    

    You would just have to run pip install asyncio before running this to use the asyncio library. Hope this fixes your issue!