CustomTkinter
CustomTkinter copied to clipboard
Default window popping-up before main window - workaround
I've seen a couple of other users encountering this in the latest version 5.0.3: https://github.com/TomSchimansky/CustomTkinter/issues/1021 https://github.com/TomSchimansky/CustomTkinter/issues/960
I'm not sure exactly where the problem is but I know its when creating a customtkinter.CTk() window, which is inside the ctk_tk.py script of the the customtkinter package.
I found some of the issues relate to wm_iconbitmap() but I wasn't calling this method.
https://stackoverflow.com/questions/55890931/python-tkinter-small-window-pops-up-momentarily-before-main-window https://stackoverflow.com/questions/15496835/python-tkinter-child-window-issue?rq=1
A workaround is to create your main window as a regular tkinter.Tk() window instead of a customtkinter window, and then create a customtkinter.CTkFrame() inside the main window so you can still use all the customtkinter methods and dependencies. This stops the small default window from popping up as the tk.Tk() window doesn't experience this issue.
Example:
import tkinter as tk
import customtkinter as ct
class AppFrame(ct.CTkFrame):
def __init__(self):
super(AppFrame, self).__init__(main_window)
main_window.geometry('250x100+600+200')
main_window.title("Main Window")
self.button = ct.CTkButton(self, text="Button!", command=self.button_command, fg_color="#000000", corner_radius=5, hover_color="#27af42", text_color="#FFFFFF", font=("Tahoma",11), width=15)
self.button.pack(pady=8, padx=8)
self.pack(pady=25)
def button_command(self):
print('hello world')
if __name__ == '__main__':
main_window = tk.Tk()
app_frame = AppFrame()
main_window.mainloop()
Workaround
I found another workaround, by overriding and restoring tkinter iconbitmap
variable.
Example:
import sys,os
import customtkinter as ct
# get customtkinder dir absolute path
customtkinter_directory= os.path.dirname(os.path.dirname(os.path.abspath(sys.modules[ct.CTk.__module__].__file__)))
# I like the customtkinter icon but it can be any icon path. just store the path in bitmap
bitmap = os.path.join(customtkinter_directory, "assets", "icons", "CustomTkinter_icon_Windows.ico")
class App(ct.CTk):
def __init__(self):
self.iconbitmap = lambda bitmap: self.wm_iconbitmap() # override iconbitmap prevent CTk.__init__ from updating the icon
super().__init__()
self.geometry(f"{600}x{500}")
self.title("CTk example")
app = App()
app.iconbitmap = app.wm_iconbitmap # restore iconbitmap value
app.iconbitmap(bitmap) # change the icon as usual
app.mainloop()
Bug Fix Suggestions
I figure out that this issue comes from calling self.iconbitmap at CTk,init:
try:
# Set Windows titlebar icon
if sys.platform.startswith("win"):
customtkinter_directory = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
self.iconbitmap(os.path.join(customtkinter_directory, "assets", "icons", "CustomTkinter_icon_Windows.ico"))
except Exception:
pass
That actually calls the tk.call
in tk.wm_iconbitmap
method:
def wm_iconbitmap(self, bitmap=None, default=None):
"""Set bitmap for the iconified widget to BITMAP. Return
the bitmap if None is given.
Under Windows, the DEFAULT parameter can be used to set the icon
for the widget and any descendants that don't have an icon set
explicitly. DEFAULT can be the relative path to a .ico file
(example: root.iconbitmap(default='myicon.ico') ). See Tk
documentation for more information."""
if default:
return self.tk.call('wm', 'iconbitmap', self._w, '-default', default)
else:
return self.tk.call('wm', 'iconbitmap', self._w, bitmap)
modifying wm_iconbitmap
so it will always use the default icon, makes the issue gone. so it might actually be an issue with Tkinter?
Anyway, I found two solutions, not sure how good they are.
- By using
after()
orafter_idle()
method when callingself.iconbitmap
in theCTk.__init__
code above, it seems to be solved:
try:
# Set Windows titlebar icon
if sys.platform.startswith("win"):
customtkinter_directory = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
self.after(100, lambda: self.iconbitmap(os.path.join(customtkinter_directory, "assets", "icons", "CustomTkinter_icon_Windows.ico")))
except Exception:
pass
- moving the code from
CTk.__init__
toCTk.mainloop
:
def mainloop(self, *args, **kwargs):
try:
# Set Windows titlebar icon
if sys.platform.startswith("win"):
customtkinter_directory = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
self.iconbitmap(
os.path.join(customtkinter_directory, "assets", "icons", "CustomTkinter_icon_Windows.ico"))
except Exception:
pass
if not self._window_exists:
self._window_exists = True
if sys.platform.startswith("win"):
if not self._withdraw_called_before_window_exists and not self._iconify_called_before_window_exists:
# print("window dont exists -> deiconify in mainloop")
self.deiconify()
super().mainloop(*args, **kwargs)
I hope that will help.