-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Open
Description
Description
In CTkEntry.__init__
, a trace_add
callback is attached to self._textvariable
:
if not (self._textvariable is None or self._textvariable == ""):
self._textvariable_callback_name = self._textvariable.trace_add("write", self._textvariable_callback)
However, in CTkEntry.destroy()
, this trace is never removed.
If the tkinter.Variable
outlives the widget, the callback can still fire after the widget is destroyed, causing TclError: invalid command name
when _textvariable_callback
tries to access self._entry
.
Example with a top-level dialog:
import customtkinter as ctk
import tkinter as tk
def open_dialog():
dialog = ctk.CTkToplevel(root)
dialog.title("Dialog with CTkEntry")
# Reuse the same StringVar every time
entry = ctk.CTkEntry(dialog, textvariable=shared_var, placeholder_text="Type here...")
entry.pack(padx=20, pady=20)
ctk.CTkButton(dialog, text="Close", command=dialog.destroy).pack(pady=10)
root = ctk.CTk()
root.geometry("300x200")
# This variable persists beyond the lifetime of any CTkEntry
shared_var = tk.StringVar(value="Default text")
ctk.CTkButton(root, text="Open Dialog", command=open_dialog).pack(pady=50)
root.mainloop()
Steps to reproduce issue:
- Open dialog, type in entry: this works fine.
- Close dialog.
- Open dialog again.
- Typing at the end of existing text works fine (no errors).
- Select all text in the entry and type something new. Now observing this error inside the terminal:
_tkinter.TclError: invalid command name ".!ctktoplevel.!ctkentry.!entry"
Note: The issue is more visible when reusing the same StringVar across dialogs.
Appending text works fine, but replacing all text (select all + type) causes the error because it triggers the placeholder logic on a destroyed widget.
Proposed fix: destroy()
should remove the trace from self._textvariable
before destroying the widget.
def destroy(self):
if self._textvariable and self._textvariable_callback_name:
try:
self._textvariable.trace_remove("write", self._textvariable_callback_name)
except Exception:
pass
self._textvariable_callback_name = ""
if isinstance(self._font, CTkFont):
self._font.remove_size_configure_callback(self._update_font)
super().destroy()
dipeshSam
Metadata
Metadata
Assignees
Labels
No labels