How to put iconbitmap on a CustomTkinter TopLevel?

Question:

This is the code example:

class ToplevelWindow(customtkinter.CTkToplevel):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.geometry("400x300")
        self.title("New Window")
        self.resizable(False, False)
        self.iconbitmap('icon.ico')
        self.after(100, self.lift)

class App(customtkinter.CTk):

    def __init__(self):
        super().__init__()

        self.geometry("550x150")
        self.title("Title")
        self.resizable(False, False)
        logo_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "test_images")
        self.logo = customtkinter.CTkImage(
            Image.open(os.path.join(logo_path, "MCB.png")),
            size=(90, 54))
        self.labelimage = customtkinter.CTkLabel(master=self, text=None, image=self.logo)
        self.labelimage.place(relx=0, rely=0, anchor=tkinter.NW)

        self.iconbitmap('icon.ico')

        self.button = customtkinter.CTkButton(master=self, text="Close", command=self.close)
        self.button.place(relx=0.675, rely=0.8, anchor=tkinter.CENTER)

        self.button2 = customtkinter.CTkButton(master=self, text="New Window", 
command=self.open_toplevel)
        self.button2.place(relx=0.325, rely=0.80, anchor=tkinter.CENTER)

        self.toplevel_window = None

    
    def close(self):

        "nothing here yet"

    def open_toplevel(self):
        if self.toplevel_window is None or not self.toplevel_window.winfo_exists():
            self.toplevel_window = ToplevelWindow(self)  # create window if its None or 
destroyed
        else:
            self.toplevel_window.focus()  # if window exists focus it

When i use the iconbitmap on the main window it works fine.
But when is used at the toplevel class, it does nothing. The icon still appears as the default version.

What i’m missing ?
How can i make this right or is it even possible ?

Answers:

This is a bug of customtkinter. If you look into the source code of CTkToplevel, there is below code inside __init__():

class CTkToplevel(tkinter.Toplevel, ...):
    def __init__(self, ...):
        ...
        try:
            # Set Windows titlebar icon
            if sys.platform.startswith("win"):
                customtkinter_directory = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
                self.after(200, lambda: self.iconbitmap(os.path.join(customtkinter_directory, "assets", "icons", "CustomTkinter_icon_Windows.ico")))
        except Exception:
            pass
        ...

So an after job is scheduled to change the window icon after 200ms which overrides your call of self.iconbitmap('icon.ico').

The above code block does not exist in the source code of CTk class, so the main window shows the icon you want.

To overcome it, you can delay your call of self.iconbitmap(...) using .after() as well:

class ToplevelWindow(...):
    def __init__(...):
        ...
        self.after(250, lambda: self.iconbitmap('icon.ico'))
        ...
Answered By: acw1668
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.