This is my debut on this site, so I will start short with introducing myself. I’m Thomas from Denmark, I hold a bachelor's degree in construction engineering and I’m trying to learn to program in Python in my spare time. So, it’s fair to say that I’m a bit of a dumbass when it comes to programming, so I hope you guys can help me.
I have attached two images of the program so it’s easier to imagine what’s going on.
My issue with the program is that when I set any one of the entry fields to an empty string, I get an TclError. But this only happens if it’s the second time I have created that frame “ForsideMenuFrame” or “LastarrangementMenuFrame”. So, I think it has something to do with when I destroy the frames. I do it to “clean up” after myself so the program performs better, or at least that is what I think. The message I get in the output is:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\Thoma\AppData\Local\Programs\Python\Python311\Lib\tkinter\__init__.py", line 1948, in __call__
return self.func(*args)
^^^^^^^^^^^^^^^^
File "C:\Users\Thoma\AppData\Local\Programs\Python\Python311\Lib\site-packages\customtkinter\windows\widgets\ctk_entry.py", line 121, in _textvariable_callback
self._activate_placeholder()
File "C:\Users\Thoma\AppData\Local\Programs\Python\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:\Users\Thoma\AppData\Local\Programs\Python\Python311\Lib\tkinter\__init__.py", line 3109, in get
return self.tk.call(self._w, 'get')
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_tkinter.TclError: invalid command name ".!lastarrangementmenuframe.!ctkentry.!entry"
The program does not crash, it still functions the way I want it to, it just bugs me, and I can’t figure out how to prevent it.
Below you see a copy of my code, and the images should be attached in the buttom.
import customtkinter as ctk
import settings, forside, lastarrangement, tagudformning
class App(ctk.CTk):
def __init__(self):
# Setup
super().__init__(fg_color = settings.BACKGROUND_COLOR)
self.title('Snelaster')
self.geometry('1400x850+50+3')
self._set_appearance_mode('dark')
self.iconbitmap('Snow_flake.ico')
self.resizable(False, False)
# Layout
self.rowconfigure(0, weight = 1, uniform = 'a')
self.rowconfigure(1, weight = 24, uniform = 'a')
self.columnconfigure(0, weight = 1, uniform = 'a')
self.columnconfigure(1, weight = 3, uniform = 'a')
# Dictionary for frames
self.frames = {
'forside_menu': None,
'forside_screen': None,
'forside_header': None,
'lastarrangement_menu': None,
'lastarrangement_screen': None,
'lastarrangement_header': None,
'pulttag_menu': None,
'pulttag_screen': None,
'pulttag_header': None,
'sadeltag_menu': None,
'sadeltag_screen': None,
'sadeltag_header': None}
# Dictionary for StringVars
self.string_vars = {
'entry_sag': ctk.StringVar(),
'entry_sagsnr': ctk.StringVar(),
'entry_initialer': ctk.StringVar(),
'entry_dato': ctk.StringVar()}
# Dictionary for StringVars with tracing
self.traced_string_vars01 = {
'entry_C_t': ctk.StringVar(value = '1.0'),
'combobox_C_top': ctk.StringVar(value = 'Normal'),
'label_C_top': ctk.StringVar(value = 'C_top\t=\t1.00'),
'entry_l_1': ctk.StringVar(value = ''),
'entry_l_2': ctk.StringVar(value = ''),
'entry_h': ctk.StringVar(value = ''),
'label_C_s': ctk.StringVar(value = 'C_s\t=\t1.00'),
'label_C_e': ctk.StringVar(value = 'C_e\t=\t1.00')}
# Start tracing of StringVars
self.start_trace_string_vars01()
# Instance of ButtonFrame
self.button_frame = ButtonFrame(self)
self.forside_button_click()
# Run
self.mainloop()
# Button commands
def forside_button_click(self):
# Change button colors
self.button_frame.forside_button.configure(fg_color = settings.FORSIDEHEADER_FRAME_COLOR_DARK)
self.button_frame.lastarrangement_button.configure(fg_color = settings.LASTARRANGEMENTHEADER_FRAME_COLOR)
self.button_frame.formfaktor_button.configure(fg_color = settings.FORMFAKTORHEADER_FRAME_COLOR)
# Destroying exsisting frames
self.destroy_frames()
# Creating Forside Menu Frame
self.frames['forside_menu'] = forside.ForsideMenuFrame(self,
self.string_vars['entry_sag'],
self.string_vars['entry_sagsnr'],
self.string_vars['entry_initialer'],
self.string_vars['entry_dato'])
# Creating Forside Screen Frame
self.frames['forside_screen'] = forside.ForsideScreenFrame(self)
# Creating Forside Header Frame
self.frames['forside_header'] = forside.ForsideHeaderFrame(self)
def lastarrangement_button_click(self):
# Change button colors
self.button_frame.forside_button.configure(fg_color = settings.FORSIDEHEADER_FRAME_COLOR)
self.button_frame.lastarrangement_button.configure(fg_color = settings.LASTARRANGEMENTHEADER_FRAME_COLOR_DARK)
self.button_frame.formfaktor_button.configure(fg_color = settings.FORMFAKTORHEADER_FRAME_COLOR)
# Destroying exsisting frames
self.destroy_frames()
# Creating Lastarrangement Menu Frame
self.frames['lastarrangement_menu'] = lastarrangement.LastarrangementMenuFrame(self,
self.traced_string_vars01['entry_C_t'],
self.traced_string_vars01['combobox_C_top'],
self.traced_string_vars01['label_C_top'],
self.traced_string_vars01['entry_l_1'],
self.traced_string_vars01['entry_l_2'],
self.traced_string_vars01['entry_h'],
self.traced_string_vars01['label_C_s'],
self.traced_string_vars01['label_C_e'])
# Creating Lastarrangement Screen Frame
self.frames['lastarrangement_screen'] = lastarrangement.LastarrangementScreenFrame(self)
# Creating Lastarrangement Header Frame
self.frames['lastarrangement_header'] = lastarrangement.LastarrangementHeaderFrame(self)
def formfaktor_button_click(self):
# Change button colors
self.button_frame.forside_button.configure(fg_color = settings.FORSIDEHEADER_FRAME_COLOR)
self.button_frame.lastarrangement_button.configure(fg_color = settings.LASTARRANGEMENTHEADER_FRAME_COLOR)
self.button_frame.formfaktor_button.configure(fg_color = settings.FORMFAKTORHEADER_FRAME_COLOR_DARK)
# Destroying exsisting frames
self.destroy_frames()
# Creating Formfaktor Menu Frame
self.frames['pulttag_menu'] = tagudformning.PulttagMenuFrame(self)
# Creating Formfaktor Screen Frame
self.frames['pulttag_screen'] = tagudformning.PulttagScreenFrame(self)
# Creating Formfaktor Header Frame
self.frames['pulttag_header'] = tagudformning.PulttagHeaderFrame(self)
def destroy_frames(self):
for key, value in self.frames.items():
if value is not None:
# Destroying the frame
self.frames[key].destroy()
self.frames[key] = None
def start_trace_string_vars01(self):
for value in self.traced_string_vars01.values():
value.trace('w', self.trace_string_vars01)
def trace_string_vars01(self, *args):
# entry_C_t
C_t = self.traced_string_vars01['entry_C_t'].get()
if len(C_t) == 2 and C_t[0] == '0' and C_t[1] != '.' or len(C_t) > 0 and C_t[0] == '.':
self.traced_string_vars01['entry_C_t'].set('0')
try:
C_t = float(C_t)
if C_t > 1:
self.traced_string_vars01['entry_C_t'].set('1.0')
except ValueError:
if C_t == '':
pass
else:
self.traced_string_vars01['entry_C_t'].set('')
# label_C_top
topografi = self.traced_string_vars01['combobox_C_top'].get()
C_top = 1.00
if topografi == 'Afskærmet':
C_top = 1.25
elif topografi == 'Normal':
C_top = 1.00
elif topografi == 'Vindblæst':
C_top = 0.80
self.traced_string_vars01['label_C_top'].set(f'C_top\t=\t{C_top:.2f}')
# entry l_1
l_1 = self.traced_string_vars01['entry_l_1'].get()
if len(l_1) == 2 and l_1[0] == '0' and l_1[1] != '.' or len(l_1) > 0 and l_1[0] == '.':
self.traced_string_vars01['entry_l_1'].set('')
try:
l_1 = float(l_1)
except ValueError:
if l_1 == '':
pass
else:
self.traced_string_vars01['entry_l_1'].set('')
# entry l_2
l_2 = self.traced_string_vars01['entry_l_2'].get()
if len(l_2) == 2 and l_2[0] == '0' and l_2[1] != '.' or len(l_2) > 0 and l_2[0] == '.':
self.traced_string_vars01['entry_l_2'].set('')
try:
l_2 = float(l_2)
except ValueError:
if l_2 == '':
pass
else:
self.traced_string_vars01['entry_l_2'].set('')
# entry h
h = self.traced_string_vars01['entry_h'].get()
if len(h) == 2 and h[0] == '0' and h[1] != '.' or len(h) > 0 and h[0] == '.':
self.traced_string_vars01['entry_h'].set('')
try:
h = float(h)
except ValueError:
if h == '':
pass
else:
self.traced_string_vars01['entry_h'].set('')
# label C_s
try:
C_s = 1.00
if topografi == 'Afskærmet':
C_s = 1.00
elif 2 * h > l_1:
C_s = 1.00
else:
if l_2 <= 10 * h:
C_s = 1.00
elif l_2 >= 20 * h:
C_s = 1.25
else:
C_s = 1 + 0.025 * ((l_2 - 10 * h) / h)
self.traced_string_vars01['label_C_s'].set(f'C_s\t=\t{C_s:.2f}')
except TypeError:
pass
# label C_e
C_e = C_top * C_s
self.traced_string_vars01['label_C_e'].set(f'C_e\t=\t{C_e:.2f}')
class ButtonFrame(ctk.CTkFrame):
def __init__(self, parent):
# Setup
super().__init__(master = parent,
fg_color = settings.BUTTON_FRAME_COLOR)
self.grid(row = 0, column = 0, sticky = 'nsew')
# Create instance of parent (App)
self.parent = parent
# Layout
self.rowconfigure(0, weight = 1, uniform = 'a')
self.columnconfigure((0,1,2), weight = 1, uniform = 'a')
# Button font
font = ctk.CTkFont(family = settings.FONT_FAMILY,
size = settings.BUTTON_FONT_SIZE,
weight = 'bold')
# Button widgets
self.forside_button = ctk.CTkButton(self,
text = 'Forside',
font = font,
text_color = 'white',
fg_color = settings.FORSIDEHEADER_FRAME_COLOR,
hover_color = settings.FORSIDEHEADER_FRAME_COLOR_DARK,
corner_radius = settings.BUTTON_CORNER_RADIUS,
command = self.parent.forside_button_click)
self.forside_button.grid(row = 0, column = 0,
sticky = 'nsew')
self.lastarrangement_button = ctk.CTkButton(self,
text = 'Lastarrangement',
font = font,
text_color = 'white',
fg_color = settings.LASTARRANGEMENTHEADER_FRAME_COLOR,
hover_color = settings.LASTARRANGEMENTHEADER_FRAME_COLOR_DARK,
corner_radius = settings.BUTTON_CORNER_RADIUS,
command = self.parent.lastarrangement_button_click)
self.lastarrangement_button.grid(row = 0, column = 1,
sticky = 'nsew')
self.formfaktor_button = ctk.CTkButton(self,
text = 'Formfaktor',
font = font,
text_color = 'white',
fg_color = settings.FORMFAKTORHEADER_FRAME_COLOR,
hover_color = settings.FORMFAKTORHEADER_FRAME_COLOR_DARK,
corner_radius = settings.BUTTON_CORNER_RADIUS,
command = self.parent.formfaktor_button_click)
self.formfaktor_button.grid(row = 0, column = 2,
sticky = 'nsew')
if __name__ == '__main__':
App()
This is what I have tried, and it did not work. In the start of the program, I imported _tkinter.
import customtkinter as ctk
import settings, forside, lastarrangement, tagudformning
import _tkinter as _tk
And then in the trace_string_vars01 method of the App class I tried to except a TclError and then ignored it.
# entry_C_t
try:
C_t = self.traced_string_vars01['entry_C_t'].get()
if len(C_t) == 2 and C_t[0] == '0' and C_t[1] != '.' or len(C_t) > 0 and C_t[0] == '.':
self.traced_string_vars01['entry_C_t'].set('0')
try:
C_t = float(C_t)
if C_t > 1:
self.traced_string_vars01['entry_C_t'].set('1.0')
except ValueError:
if C_t == '':
pass
else:
self.traced_string_vars01['entry_C_t'].set('')
except _tk.TclError:
pass
The error suggests it comes within the
costumtkinterpackage and the source code give you multiple options where the error might happen.Setting the variable to an empty string, by configure placeholder, FocusOut, delete method or by instantiating a Entry.
Further, your error refering to this Entry:
".!lastarrangementmenuframe.!ctkentry.!entry"Even though you included a lot of code, it's not enough in this case, since
lastarrangement.LastarrangementMenuFrameis defined in an imported module.The error:
means that you/the
StringVaror an event refering to an already dead widget.