CustomTkinter
CustomTkinter copied to clipboard
Progress Bar Freezing When Moving the Window During Update
Dear All,
Issue: The progress bar freezes when the user tries to move the window while the progress is being updated. Although the progress continues in the background (e.g., printed logs show updates), the UI becomes unresponsive. I'm looking for suggestions on how to allow the user to move the window without freezing the progress bar or the overall system.
Steps to Reproduce:
- Run the provided code.
- Start the progress by clicking "Start Progress."
- Attempt to move the window while the progress bar is updating.
Expected Behavior: The window should be movable without causing the progress bar to freeze or the UI to become unresponsive.
Actual Behavior: The progress bar freezes when the window is moved, even though progress updates continue in the terminal.
Code Example:
import time
import customtkinter as ctk
class App(ctk.CTk):
def __init__(self):
super().__init__()
# configure window
self.title("Freezing Progressbar")
# create slider and progressbar frame
self.slider_progressbar_frame = ctk.CTkFrame(self, fg_color="transparent")
self.slider_progressbar_frame.grid(row=0, column=0, padx=(20, 0), pady=(20, 0), sticky="nsew")
self.sidebar_button_1 = ctk.CTkButton(self.slider_progressbar_frame, text='Start Progress', command=self.sidebar_button_event)
self.sidebar_button_1.grid(row=0, column=0, padx=20, pady=10)
self.progressbar_1 = ctk.CTkProgressBar(self.slider_progressbar_frame, height=15)
self.progressbar_1.grid(row=1, column=0, padx=(20, 10), pady=(10, 10), sticky="ew")
self.progressbar_1.set(0)
def sidebar_button_event(self):
self.test()
print("sidebar_button click")
def test(self):
duration = 10
iter_step = 1/duration
progress_step = iter_step
self.progressbar_1.start()
for i in range(duration):
print(progress_step)
self.progressbar_1.set(progress_step)
time.sleep(1)
progress_step += iter_step
self.update_idletasks()
self.progressbar_1.stop()
if __name__ == "__main__":
app = App()
app.mainloop()
Preview: https://github.com/user-attachments/assets/5b733b23-aa6d-43c5-b4aa-5a595f14514a
Environment: OS: Window 11 Python Version: 3.10.4 CustomTkinter Version: 5.2.2 Any ideas or recommendations would be appreciated!
Since CustomTkinter does not inherently support threading within its callbacks, any long-running tasks will cause the entire interface—including window movements and other functionalities—to freeze or become temporarily unresponsive until the task completes. This is because such tasks block the GUI event loop. To handle operations that take longer than what the GUI loop can manage smoothly, it’s essential to offload them to a separate thread manually.
Also, in your provided sample code, there's a minor bug: when setting the progress bar's value incrementally, it's unnecessary to call start method on the progressbar. The corrected version of the code is given below:
import time
import customtkinter as ctk
from threading import Thread
class App(ctk.CTk):
def __init__(self):
super().__init__()
# configure window
self.title("Freezing Progressbar")
# create slider and progressbar frame
self.slider_progressbar_frame = ctk.CTkFrame(self, fg_color="transparent")
self.slider_progressbar_frame.grid(row=0, column=0, padx=(20, 0), pady=(20, 0), sticky="nsew")
self.sidebar_button_1 = ctk.CTkButton(self.slider_progressbar_frame, text='Start Progress', command=self.sidebar_button_event)
self.sidebar_button_1.grid(row=0, column=0, padx=20, pady=10)
self.progressbar_1 = ctk.CTkProgressBar(self.slider_progressbar_frame, height=15)
self.progressbar_1.grid(row=1, column=0, padx=(20, 10), pady=(10, 10), sticky="ew")
self.progressbar_1.set(0)
def sidebar_button_event(self):
Thread(target=self.test, daemon=True).start()
print("sidebar_button click")
def test(self):
duration = 10
iter_step = 1/duration
progress_step = iter_step
for i in range(duration):
print(progress_step)
self.progressbar_1.set(progress_step)
time.sleep(1)
progress_step += iter_step
self.update_idletasks()
self.progressbar_1.stop()
if __name__ == "__main__":
app = App()
app.mainloop()
Output:
Additionally, you could use .after() method for better handling such tasks in Tkinter or CustomTkinter. Hope the above information would be helpful to you.
Regards