TomSchimansky / CustomTkinter

A modern and customizable python UI-library based on Tkinter
MIT License
10.99k stars 1.04k forks source link

CTkEntry _textvariable_callback issue #1981

Open Lutheine opened 10 months ago

Lutheine commented 10 months ago

Hi Tom, I'm experiencing alike issue right now, but the difference is that widget throwing exception error is CTkEntry. I'm doing dynamic UI and when trying to destroy widget, I want to empty out any text in textvariable stringVar stored, so I can reuse the same variable if widget is created again. After destroying a widget, textvariable can't be .set('') without error, while .set('%anything%') doesn't throw exceptions.

Code:

from customtkinter import CTk, CTkEntry, CTkComboBox
from tkinter import StringVar

root = CTk()

TEST = StringVar()

def clear():
    for c in root.winfo_children():
        c.destroy()

def load():
    test = CTkEntry(root, textvariable=TEST)
    test.pack()

TEST.set("") #no error
load()
TEST.set("") #no error
clear()
TEST.set("") #throws error, but still works, stringvar changes to ''
TEST.set("%") #no error

root.mainloop()

Error:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Program Files\Python311\Lib\tkinter\__init__.py", line 1948, in __call__
    return self.func(*args)
           ^^^^^^^^^^^^^^^^
  File "C:\Program Files\Python311\Lib\site-packages\customtkinter\windows\widgets\ctk_entry.py", line 121, in _textvariable_callback
    self._activate_placeholder()
  File "C:\Program Files\Python311\Lib\site-packages\customtkinter\windows\widgets\ctk_entry.py", line 299, in _activate_placeholder
    if self._entry.get() == "" and self._placeholder_text is not None and (self._textvariable is None or self._textvariable == ""):
       ^^^^^^^^^^^^^^^^^
  File "C:\Program Files\Python311\Lib\tkinter\__init__.py", line 3099, in get
    return self.tk.call(self._w, 'get')
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_tkinter.TclError: invalid command name ".!ctkentry.!entry"

Originally posted by @Lutheine in https://github.com/TomSchimansky/CustomTkinter/issues/468#issuecomment-1713529172

its-ahad commented 10 months ago

Use TEST.set(None) and update the load function as follow. def load(): if TEST.get() != 'None': test = CTkEntry(root, textvariable=TEST) test.pack() Hopefully this will resolve your issue

Lutheine commented 10 months ago

Hi Ahad, that doesn't solve the problem just because None is being treated like string 'None' and causes the variable to be 4 length while I need it to be 0, when variable is not in use. It's no different than assigning variable to any string, I currently workaround with ' ' instead of '' and then later use check if len(var.strip()) == 0.

Have a look:

TEST = StringVar()
TEST.set(None)
print(len(TEST.get()))      #result is 4, while should be 0 for my needs
print(type(Test.get()))     #results in class type of str
print(type(None))           #it's class type of NoneType