I am trying to make an app with Tkinter and CustomTkinter and sometimes it fails saying that ir has reached the maximum recursion depth. The error usually happens when rescaling a view and less often when openning new windows. The following example fails when rescaling:
import tkinter as tk
from hdpitkinter import HdpiTk
import customtkinter as ctk
import ctypes
def rescale(event, root, frames, scrolls):
scale_factor = ctypes.windll.shcore.GetScaleFactorForDevice(0)/100
print(scale_factor)
width = root.winfo_width()//scale_factor
height = root.winfo_height()//scale_factor
print("Width = ", width, "Height = ", height, "type", type(width))
for i in range(3):
frames[i].configure(width = width-10,height=(height//3)-30)
scrolls[i].configure(width = (width/2)-40,height=(height//3)-50)
scrolls[i+3].configure(width = (width/2)-40,height=(height//3)-50)
# Updates window
root.update_idletasks()
if __name__ == "__main__":
root = ctk.CTk()
root.geometry("1280x720")
root.minsize(width=1280,height=720)
root.title("Test")
root.configure(fg_color = "#4B4B4B")
height = 720
width = 1280
frames, scrolls, labels = [], [], []
leftFont = ctk.CTkFont(family="Inter", size=20, weight="normal")
rightFont = ctk.CTkFont(family="Inter", size=15, weight="normal")
# Base frames creation
for i in range(3):
frames.append(ctk.CTkFrame(master=root,fg_color="#504F4F", corner_radius=10, width = width-10, height=height/3-46))
# ScrollFrames creation
for i in range(6):
scrolls.append(ctk.CTkScrollableFrame(master=frames[i%3],fg_color="#504F4F", corner_radius= 10,width = ((width/2)-40)))
# Buttons creation
button1 = ctk.CTkButton(root, text="button1", font=leftFont, corner_radius=10,
fg_color="#1E1E1E", text_color="white", height=40)
button2 = ctk.CTkButton(root, text="button2", font=leftFont, corner_radius=10,
fg_color="#1E1E1E", text_color="white", height=40)
button3 = ctk.CTkButton(root, text="button3", font=leftFont, corner_radius=10,
fg_color="#1E1E1E", text_color="white", height=40)
# Placing of buttons
button1.grid(column = 0, row = 3,pady = 5, padx = 10, sticky="w")
button2.grid(column = 1, row = 3,pady = 5, padx = 10, sticky="w")
button3.grid(column = 1, row = 3,pady = 5, sticky="e")
# Frames placing
for i in range(3):
frames[i].grid(column= 0, row = i, columnspan=2, padx=3, pady=3,)
# Scrolls and labels placing
for i in range(3):
scrolls[i].grid(row = 0, column=0, padx = 5)
scrolls[i+3].grid(row = 0, column=1, padx = 5)
# Bind rescale method
root.bind("<Configure>", lambda event, root = root, frames = frames, scrolls = scrolls: rescale(event, root, frames, scrolls))
root.mainloop()
The complete error is this:
Traceback (most recent call last):
File "d:\lib\tkinter\__init__.py", line 1921, in __call__
return self.func(*args)
File "D:\test.py", line 58, in <lambda>
root.bind("<Configure>", lambda event, root = root, frames = frames, scrolls = scrolls: rescale(event, root, frames, scrolls))
File "D:\test.py", line 13, in rescale
frames[i].configure(width = width-10,height=(height//3)-30)
File "d:\lib\site-packages\customtkinter\windows\widgets\ctk_frame.py", line 167, in configure
super().configure(require_redraw=require_redraw, **kwargs)
File "d:\lib\site-packages\customtkinter\windows\widgets\core_widget_classes\ctk_base_class.py", line 117, in configure
self._set_dimensions(width=kwargs.pop("width"))
File "d:\lib\site-packages\customtkinter\windows\widgets\ctk_frame.py", line 88, in _set_dimensions
super()._set_dimensions(width, height)
File "d:\lib\site-packages\customtkinter\windows\widgets\core_widget_classes\ctk_base_class.py", line 240, in _set_dimensions
super().configure(width=self._apply_widget_scaling(self._desired_width),
RecursionError: maximum recursion depth exceeded while calling a Python object
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "D:\test.py", line 59, in <module>
root.mainloop()
File "d:\lib\site-packages\customtkinter\windows\ctk_tk.py", line 165, in mainloop
super().mainloop(*args, **kwargs)
File "d:\lib\tkinter\__init__.py", line 1458, in mainloop
self.tk.mainloop(n)
File "d:\lib\tkinter\__init__.py", line 1925, in __call__
self.widget._report_exception()
File "d:\lib\tkinter\__init__.py", line 1641, in _report_exception
root.report_callback_exception(exc, val, tb)
File "d:\lib\tkinter\__init__.py", line 2379, in report_callback_exception
traceback.print_exception(exc, val, tb)
File "d:\lib\traceback.py", line 119, in print_exception
te = TracebackException(type(value), value, tb, limit=limit, compact=True)
File "d:\lib\traceback.py", line 502, in __init__
self.stack = StackSummary.extract(
File "\lib\traceback.py", line 353, in extract
limit = getattr(sys, 'tracebacklimit', None)
RecursionError: maximum recursion depth exceeded while calling a Python object
I found out that changing frames[i].configure(width = width-10,height=(height//3)-35)
with frames[i].configure(width = width-10,height=(height//3)-30)
does work, it takes a long time to update but works. Also the problem is not just with rescaling as such because in the project I have a main window that opens other windows and it also trhows the error when creating some of them.
Another thing I found is that if i create a new conda enviroment does solve the problem, it still takes a long time to load the window but it does it.
So my question, is there a way to make sure that this wont happen if I install it elsewhere or if I compile it into an exe?
As told in the comments above every time a widget is updated it generates an event, and since inside that event we update widgets this rescaling method is called infinitely.
My solution has been to do the rescaling only if more than half a second has passed since last time it executed:
def rescale(event, root, frames, scrolls):
global updated
if(time.time()- updated > 0.5 ):
scale_factor = ctypes.windll.shcore.GetScaleFactorForDevice(0)/100
print(scale_factor)
width = root.winfo_width()//scale_factor
height = root.winfo_height()//scale_factor
print("Width = ", width, "Height = ", height, "type", type(width))
for i in range(3):
frames[i].configure(width = width-10,height=(height//3)-80)
scrolls[i].configure(width = (width/2)-40,height=(height//3)-45)
scrolls[i+3].configure(width = (width/2)-40,height=(height//3)-45)
# Updates window
#root.update_idletasks()
updated = time.time()
This works and is a lot faster than when the other attempt worked.