TomSchimansky / TomSchimansky/CustomTkinter
CTkImage on setting inside a label throws (_tkinter.TclError: image "pyimage4" doesn't exist) error
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 13.6k
- Forks
- 1.2k
- PR merge metrics
- No merged PRs in 30d
Description
I am working on pycharm so the error is not Spyder specific as some were saying on stackoverflow. i tries runnign the program on the global system terminal still the same error.
Code
class EyeButton:
def __init__(self, master: customtkinter.CTkEntry, hide_char: str):
self.master = master
self.hide_char = hide_char
self.unhide = customtkinter.CTkImage(dark_image=Image.open("Eye.png"), size=(22, 18))
self.hide = customtkinter.CTkImage(dark_image=Image.open("NotEye.png"), size=(24, 20))
self.buttonLabel = customtkinter.CTkLabel(master=self.master, font=('Roboto', 12), text='', image=self.unhide, fg_color='transparent', height=self.master.winfo_height()-10) # Traces back error to this line while defining the image self.unhide
def initialize(self):
self.buttonLabel.bind("<Button-1>", lambda e: self.state())
self.buttonLabel.place(relx=0.99, rely=0.5, anchor='e')
self.tracker = 1
def state(self):
if self.tracker == 1:
self.master.configure(show="")
self.buttonLabel.configure(image=self.hide)
self.tracker = False
else:
self.master.configure(show=self.hide_char)
self.buttonLabel.configure(image=self.unhide)
self.tracker = True
self.tracker *= 1
def login_box():
ConnectionWin.after(200, lambda: threading.Thread(target=ConnectionWin.destroy).start())
box = customtkinter.CTk()
box.title("PyChat Login")
box.iconbitmap('PyChat.ico')
w = 400
h = 410
box.geometry(get_geo(box, w, h))
frame = customtkinter.CTkFrame(master=box)
frame.pack(pady=20, padx=40, fill="both", expand=True)
uname = customtkinter.CTkEntry(master=frame, placeholder_text="Username", width=240)
uname.pack(pady=12, padx=10)
passwd = customtkinter.CTkEntry(master=frame, placeholder_text="Password", show="•", width=240)
passwd.pack(pady=12, padx=10)
box.update()
showButton = EyeButton(master=passwd, hide_char="•") #Getting error while creating child
showButton.initialize()
LoginButton = customtkinter.CTkButton(master=frame, text="Sign in", command=login)
LoginButton.pack(pady=12, padx=10)
box.update()
box.mainloop()
The class is used to create a eye button that hides and unhides password inside the CTkEntry box. Previously it used to work fine unless i added a loading screen before the login screen that gets destroyed inside the login_box function via a thread (the ConnectionWin) but since the button is initilized before the window gets destroyed it trows the following error.
Error
Traceback (most recent call last):
File "C:\Users\Rishi\PycharmProjects\PyChat\test.py", line 253, in connect
login_box()
File "C:\Users\Rishi\PycharmProjects\PyChat\test.py", line 180, in login_box
showButton = EyeButton(master=passwd, hide_char="•")
File "C:\Users\Rishi\PycharmProjects\PyChat\test.py", line 16, in __init__
self.buttonLabel = customtkinter.CTkLabel(master=self.master, font=('Roboto', 12), text='', image=self.unhide, fg_color='transparent', height=self.master.winfo_height()-10)
File "C:\Users\Rishi\PycharmProjects\PyChat\venv\lib\site-packages\customtkinter\windows\widgets\ctk_label.py", line 93, in __init__
self._update_image()
File "C:\Users\Rishi\PycharmProjects\PyChat\venv\lib\site-packages\customtkinter\windows\widgets\ctk_label.py", line 130, in _update_image
self._label.configure(image=self._image.create_scaled_photo_image(self._get_widget_scaling(),
File "C:\Program Files\Python310\lib\tkinter\__init__.py", line 1675, in configure
return self._configure('configure', cnf, kw)
File "C:\Program Files\Python310\lib\tkinter\__init__.py", line 1665, in _configure
self.tk.call(_flatten((self._w, cmd)) + self._options(cnf))
_tkinter.TclError: image "pyimage4" doesn't exist
I tried decreasing the after() time for destroying the window but that results in another RuntimError mainthread is not inside mainloop and i also tried to disable the garbage collector so that it doesnt collect the vraible data and clear it by doing g.disable() and checked the gc state by gc.isenabled() which returned false but still the same error.
Code to replicate the error
Use a basic server to accept the connection to initiate the login window
import time
import traceback
import PIL.ImageTk
from PIL import Image
import tkinter as tk
import threading
import customtkinter
import socket as sock
class EyeButton:
def __init__(self, master: customtkinter.CTkEntry, hide_char: str):
self.master = master
self.hide_char = hide_char
self.unhide = customtkinter.CTkImage(dark_image=Image.open("Eye.png"), size=(22, 18))
self.hide = customtkinter.CTkImage(dark_image=Image.open("NotEye.png"), size=(24, 20))
self.buttonLabel = customtkinter.CTkLabel(master=self.master, text='', image=self.unhide, fg_color='transparent', height=self.master.winfo_height()-10)
self.buttonLabel.image = self.unhide
def initialize(self):
self.buttonLabel.bind("<Button-1>", lambda e: self.state())
self.buttonLabel.place(relx=0.99, rely=0.5, anchor='e')
self.tracker = 1
def state(self):
if self.tracker == 1:
self.master.configure(show="")
self.buttonLabel.configure(image=self.hide)
self.tracker = False
else:
self.master.configure(show=self.hide_char)
self.buttonLabel.configure(image=self.unhide)
self.tracker = True
self.tracker *= 1
class HyperLabel(customtkinter.CTkLabel):
def __init__(self, *args, **kwargs):
customtkinter.CTkLabel.__init__(self, *args, **kwargs)
self.bind('<Enter>', lambda e: self.on_hover())
self.bind('<Leave>', lambda e: self.on_leave())
def on_hover(self):
self.configure(text_color="#54a2de", font=('Roboto', 12, 'underline'))
def on_leave(self):
self.configure(text_color="#1f6aa5", font=('Roboto', 12))
class HyperImage(customtkinter.CTkLabel):
def __init__(self, on: customtkinter.CTkImage, off: customtkinter.CTkImage, *args, **kwargs):
self.on = on
self.off = off
customtkinter.CTkLabel.__init__(self, *args, **kwargs, image=off)
self.bind('<Enter>', lambda e: self.on_hover())
self.bind('<Leave>', lambda e: self.on_leave())
def on_hover(self):
self.configure(image=self.on)
def on_leave(self):
self.configure(image=self.off)
def get_geo(master, width, height):
screen_width = master.winfo_screenwidth()
screen_height = master.winfo_screenheight()
x = (screen_width / 2) - (width / 2)
y = (screen_height / 2) - (height / 2)
position = '%dx%d+%d+%d' % (width, height, x, y)
return position
def login_box():
ConnectionWin.after(200, lambda: threading.Thread(target=ConnectionWin.destroy).start())
box = customtkinter.CTk()
box.title("PyChat Login")
box.iconbitmap('PyChat.ico')
w = 400
h = 410
box.geometry(get_geo(box, w, h))
box.minsize(w, h)
box.maxsize(w, h)
frame = customtkinter.CTkFrame(master=box)
frame.pack(pady=20, padx=40, fill="both", expand=True)
label = customtkinter.CTkLabel(master=frame, text="Login", font=("Roboto", 24))
label.pack(pady=(12, 26), padx=10)
warning = customtkinter.CTkLabel(master=frame, text="", font=("Roboto", 12), text_color="#d94b58")
warning.pack(pady=0, padx=0)
warning.place(anchor='w', relx=0.135, rely=0.18)
uname = customtkinter.CTkEntry(master=frame, placeholder_text="Username", width=240)
uname.pack(pady=12, padx=10)
passwd = customtkinter.CTkEntry(master=frame, placeholder_text="Password", show="•", width=240)
passwd.pack(pady=12, padx=10)
box.update()
time.sleep(0.2)
showButton = EyeButton(master=passwd, hide_char="•")
showButton.initialize()
LoginButton = customtkinter.CTkButton(master=frame, text="Sign in", command=login)
LoginButton.pack(pady=12, padx=10)
remember = customtkinter.CTkCheckBox(master=frame, text="Stay Logged In")
remember.pack(pady=12, padx=10)
text = customtkinter.CTkLabel(master=frame, text="New to Pychat?", text_color="silver", font=('Roboto', 12))
signup = HyperLabel(master=frame, text="Sign up", text_color="#1f6aa5", font=('Roboto', 12))
signup.bind("<Button-1>", lambda e: register())
text.pack(pady=8, padx=2)
signup.pack(pady=8, padx=2)
box.update()
box.mainloop()
def splash():
global SplashWin
SplashWin = customtkinter.CTk()
SplashWin.overrideredirect(True)
w = 350
h = 180
SplashWin.geometry(get_geo(SplashWin, w, h))
icon = customtkinter.CTkImage(dark_image=Image.open("PyChat.png"), size=(98, 98))
logo = customtkinter.CTkLabel(master=SplashWin, text="", image=icon)
logo.place(anchor='center', relx=0.3, rely=0.36)
label = customtkinter.CTkLabel(master=SplashWin, text="PyChat", font=('Roboto', 40))
label.pack(pady=0, padx=0)
label.place(anchor='w', relx=0.45, rely=0.36)
loading = customtkinter.CTkLabel(master=SplashWin, text="Loading...", font=('Roboto', 16), text_color='silver')
loading.place(relx=0.5, rely=0.7, anchor='center')
loadbar = customtkinter.CTkProgressBar(master=SplashWin, corner_radius=0, width=350, border_width=0, fg_color='#1f6aa5', progress_color='#54a2de', indeterminate_speed=1.2)
loadbar.pack(side=tk.BOTTOM, pady=0, padx=0)
loadbar.configure(mode="indeterminnate")
loadbar.start()
SplashWin.after(4000, connect)
SplashWin.mainloop()
def fail_box():
ConnectionWin.after(500, lambda: threading.Thread(target=ConnectionWin.destroy).start())
global popup
popup = customtkinter.CTk()
popup.title("PyChat Connection Error")
popup.iconbitmap('PyChat.ico')
w = 400
h = 240
popup.geometry(get_geo(popup, w, h))
popup.minsize(w, h)
popup.maxsize(w, h)
frame = customtkinter.CTkFrame(master=popup)
frame.pack(pady=20, padx=40, fill="both", expand=True)
label = customtkinter.CTkLabel(master=frame, text="Connection Failed!", font=('Roboto', 28))
label.pack(padx=20, pady=20)
error = customtkinter.CTkLabel(master=frame, text="Unable to Connect to Server\nPlease try again later.", text_color='silver', font=('Roboto', 14))
error.pack(padx=20, pady=10)
button = customtkinter.CTkButton(master=frame, text="OK", width=70, command=lambda: popup.destroy())
button.pack(padx=20, pady=20)
popup.mainloop()
def connect():
SplashWin.destroy()
global client
th = threading.Thread(target=connect_box)
th.daemon = True
th.start()
client = sock.socket(sock.AF_INET, sock.SOCK_STREAM)
time.sleep(3)
try:
client.connect(('127.0.0.1', 5574))
loadbar1.stop()
ConnectionWin.withdraw()
login_box()
except ConnectionRefusedError:
loadbar1.stop()
ConnectionWin.withdraw()
fail_box()
except ConnectionError:
loadbar1.stop()
ConnectionWin.withdraw()
fail_box()
except Exception:
print(traceback.format_exc())
exit()
def connect_box():
global ConnectionWin, loadbar1
ConnectionWin = customtkinter.CTk()
ConnectionWin.title("PyChat")
ConnectionWin.iconbitmap('PyChat.ico')
w = 400
h = 370
screen_width = ConnectionWin.winfo_screenwidth()
screen_height = ConnectionWin.winfo_screenheight()
x = (screen_width / 2) - (w / 2)
y = (screen_height / 2) - (h / 2)
position = '%dx%d+%d+%d' % (w, h, x, y)
ConnectionWin.geometry(position)
ConnectionWin.minsize(w, h)
ConnectionWin.maxsize(w, h)
icon = customtkinter.CTkImage(dark_image=Image.open("PyChat.png"), size=(98, 98))
logo = customtkinter.CTkLabel(master=ConnectionWin, text="", image=icon)
logo.place(anchor='center', relx=0.3, rely=0.14)
label = customtkinter.CTkLabel(master=ConnectionWin, text="PyChat", font=('Roboto', 40))
label.pack(pady=0, padx=0)
label.place(anchor='w', relx=0.45, rely=0.14)
frame = customtkinter.CTkFrame(master=ConnectionWin)
frame.pack(pady=(100, 20), padx=40, fill="both", expand=True)
label = customtkinter.CTkLabel(master=frame, text="Connecting to server...", font=('Roboto', 24))
label.pack(padx=40, pady=40)
loadbar1 = customtkinter.CTkProgressBar(master=frame, corner_radius=20, width=240, progress_color='#54a2de', indeterminate_speed=0.8)
loadbar1.pack(pady=0, padx=0)
loadbar1.configure(mode="indeterminnate")
loadbar1.start()
Github = customtkinter.CTkImage(dark_image=Image.open("master/sources/github.png"), size=(124, 64))
GithubHighlight = customtkinter.CTkImage(dark_image=Image.open("master/sources/github_highlight.png"), size=(124, 64))
GitLabel = HyperImage(master=ConnectionWin, text="", width=24, height=30, cursor="hand2", on=GithubHighlight, off=Github)
GitLabel.bind("<Button-1>", lambda e: print('https://github.com/TriDEntApollO?tab=repositories'))
GitLabel.pack(pady=0, padx=20)
developed = customtkinter.CTkLabel(master=ConnectionWin, text="Developed by TriDEntApollO", text_color="silver")
developed.pack(pady=(0, 20), padx=20)
ConnectionWin.mainloop()
return
customtkinter.set_appearance_mode("Dark")
customtkinter.set_default_color_theme("dark-blue")
splash()
Server code to accept the connection
import socket as sock
server = sock.socket(sock.AF_INET, sock.SOCK_STREAM)
name = sock.gethostname()
host, port = sock.gethostbyname(name), 5574
server.bind((host, port))
server.listen(1)
client, address = server.accept()
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the supplied minimal reproduction and traceback, then inspect customtkinter/windows/widgets/ctk_label.py, especially CTkLabel initialization and _update_image. Reproduce the pyimage4 failure while the other window is destroyed from a thread, and determine a maintainable project-level correction or documented limitation. Done means the reproduction no longer raises the TclError under the supported window lifecycle.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- desktop
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 35/100