pythontkintertkinter-canvastkinter-entrytkinter-text

How to hide and show canvas in tkinter python?


I have created a moving dot animation in tkinter canvas to represent loading. Whenever I input something to the text widget, it should immediately show this moving animation. After 5 seconds, it should disappear. This is the needed functionality. I don't know whats wrong with the below code. Can someone help me achieve what I've described.

import tkinter as tk
from tkinter import ttk
import time

def animate_dot(canvas, dot, dx):
    canvas.move(dot, dx, 0)
    x_pos = canvas.coords(dot)[0]
    if x_pos >= 150 or x_pos <= 50:
        dx *= -1  # Change direction when reaching the edge
    canvas.after(10, animate_dot, canvas, dot, dx)  # Increase speed by reducing the delay


def send_message(event=None):
    message = message_entry.get(1.0, "end-1c") 
    message = message.strip()
    message_entry.delete(1.0, tk.END)
    message_entry.update()

    
    if not message:
        pass 
    else:
        canvas1.place(x=510,y=90)
        canvas1.update()
        animate_dot(canvas1, dot, dx) 
        time.sleep(5)
        canvas1.forget()
             
root = tk.Tk()
root.title("Chat")

# Maximize the window
root.attributes('-zoomed', True)

canvas1 = tk.Canvas(root, width=250, height=70, bg="white", borderwidth=0, highlightthickness=0)

# Display "Loading" text
loading_text = canvas1.create_text(50, 50, text="Loading", anchor="e")

# Create a black dot
dot = canvas1.create_oval(50, 40, 60, 50, fill="black")

dx = 1  # Increase the initial movement speed



message_entry = tk.Text(root, padx=17, insertbackground='white', width=70, height=1, spacing1=20, spacing3=20, font=('Open Sans', 14))
message_entry.pack(side=tk.LEFT, padx=(500, 0), pady=(0, 70))  
message_entry.bind("<Return>", send_message)
#message_entry.bind("<Button-1>", click
message_entry.focus_set() 
root.mainloop()

Solution

  • You should avoid calling time.sleep() in the main thread because it will block tkinter mainloop() from handling pending events and updates.

    You should check whether the animation should be stopped inside animate_dot(). Suggest to add two arguments to animate_dot():

    1. countdown - how long the animation should be running in ms
    2. delay - sleep period between moving of the dot in ms

    Updated code:

    # added arguments countdown (default 5000ms) and delay (default 10ms)
    def animate_dot(canvas, dot, dx, countdown=5000, delay=10):
        canvas.move(dot, dx, 0)
        x_pos = canvas.coords(dot)[0]
        if x_pos >= 150 or x_pos <= 50:
            dx *= -1  # Change direction when reaching the edge
        if countdown > 0:
            # keep animation
            canvas.after(delay, animate_dot, canvas, dot, dx, countdown-delay, delay)  # Increase speed by reducing the delay
        else:
            # stop animation, so remove the canvas
            canvas1.place_forget()
    
    
    def send_message(event=None):
        message = message_entry.get(1.0, "end-1c")
        message = message.strip()
        message_entry.delete(1.0, tk.END)
        message_entry.update()
    
    
        if not message:
            pass
        else:
            canvas1.place(x=510,y=90)
            canvas1.update()
            animate_dot(canvas1, dot, dx)
            # don't call sleep() here
            #time.sleep(5)
            #canvas1.forget()