3

I'm new to coding/Python started a few weeks ago and am learning by creating a basic app with Customtkinter (for the aesthetic) on Pycharm. The app has 2 Customtkinter windows, a login window (class LoginWindow) and a main window (window) that opens via a button press in the login window. Closing the app on the login window without going to the main window works, however closing the app from the main window or going back to the login window and closing it then does not work and Pycharm shows the code as still running.

Here's the code below minus some widgets, etc that are unrelated to the issue:

#Imports
import tkinter as tk
from tkinter import LEFT
import customtkinter as ctk
from tkinter import messagebox

#CTk preference
ctk.set_appearance_mode('dark')
ctk.set_default_color_theme('green')

class MainFrame(ctk.CTkFrame):
    def __init__(self, master, **kwargs):
        super().__init__(master, **kwargs)
        self.configure(fg_color='transparent')

        self.tabframe = ctk.CTkFrame(self)
        self.tabframe.pack(side=LEFT, fill='both', expand=False)

        # Create buttons
        self.create_buttons()

    def create_buttons(self):
        self.logoutbutton = ctk.CTkButton(self.tabframe,
                                          text='Logout',
                                          font=('JetBrains Mono', 20, 'bold'),
                                          text_color='white',
                                          fg_color='#FF5555',
                                          hover_color='#FF3333',
                                          command=self.logout)
        self.logoutbutton.grid(row=5, column=0, padx=20, pady=20, sticky='news')

    def logout(self):
        if messagebox.askyesno("Logout", "Are you sure you want to logout?"):
            self.master.destroy()
            login = LoginWindow()
            login.run()

class LoginWindow:
    def show_main_window(self):
        window = ctk.CTk()
        window.geometry("1920x1080")
        window.state('zoomed')
        window.resizable(False, False)
        window.title('Your Finances')
        try:
            window.iconbitmap('logo.ico')
        except:
            pass

        main_frame = MainFrame(window)
        main_frame.pack(fill='both', expand=True)
        window.mainloop()

    def __init__(self):
        self.window = ctk.CTk()
        self.window.geometry('1920x1080')
        self.window.state('zoomed')
        self.window.resizable(width=False, height=False)
        self.window.title('Login')

        try:
            self.window.iconbitmap('logo.ico')
        except:
            pass

        self.frame = ctk.CTkFrame(self.window, fg_color='transparent')

        self.title = ctk.CTkLabel(self.frame,
                                 text='Login',
                                 font=('JetBrains Mono', 40, 'bold'),
                                 text_color='#2FA572',
                                 padx=20, pady=20)
        self.title.grid(row=0, column=0, padx=40, pady=40, columnspan=2, sticky='news')

        self.entryquestion = ctk.CTkLabel(self.frame,
                                         text='Password',
                                         font=('JetBrains Mono', 20),
                                         text_color='#2FA572',
                                         padx=20, pady=20)
        self.entryquestion.grid(row=1, column=0, padx=20, pady=20)

        self.user_input = tk.StringVar(self.window)
        self.password = "password"

        self.entrypassword = ctk.CTkEntry(self.frame,
                                         textvariable=self.user_input,
                                         font=('JetBrains Mono', 20),
                                         show='*')
        self.entrypassword.grid(row=1, column=1, pady=20)

        self.submitbutton = ctk.CTkButton(self.frame,
                                         text='Submit',
                                         font=('JetBrains Mono', 20, 'bold'),
                                         command=self.submit)
        self.submitbutton.grid(row=2, column=0, padx=20, pady=40)

        self.exitbutton = ctk.CTkButton(self.frame,
                                        text='Exit',
                                        font=('JetBrains Mono', 20, 'bold'),
                                        text_color='white',
                                        fg_color='#FF5555',
                                        hover_color='#FF3333',
                                        command=self.exit)
        self.exitbutton.grid(row=2, column=1, padx=20, pady=40)

        self.frame.pack()

    def submit(self):
        entered_password = self.user_input.get().strip()
        if not entered_password:
            messagebox.showwarning("Error", "Please enter a password")
            return
        if entered_password == self.password:
            self.window.withdraw()
            self.window.quit()
            self.show_main_window()
        else:
            messagebox.showerror("Error", "Incorrect password")

    def run(self):
        self.window.mainloop()

    def exit(self):
        self.window.quit()
        self.window.destroy()

if __name__ == "__main__":
    app = LoginWindow()
    app.run()

Currently stopping the code requires pressing the 'Stop' button twice in the Pycharm IDE, on first click it shows the error code below:

invalid command name "2673024703360_click_animation"
    while executing
"2673024703360_click_animation"
    ("after" script)
Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\suraj\AppData\Local\Programs\Python\Python313\Lib\tkinter\__init__.py", line 2068, in __call__
    return self.func(*args)
           ~~~~~~~~~^^^^^^^
  File "C:\Users\suraj\PycharmProjects\PythonProject\.venv\Lib\site-packages\customtkinter\windows\widgets\ctk_button.py", line 554, in _clicked
    self._command()
    ~~~~~~~~~~~~~^^
  File "C:\Users\suraj\PycharmProjects\PythonProject\Beta.py", line 208, in submit
    self.show_main_window()
    ~~~~~~~~~~~~~~~~~~~~~^^
  File "C:\Users\suraj\PycharmProjects\PythonProject\Beta.py", line 144, in show_main_window
    window.mainloop()
    ~~~~~~~~~~~~~~~^^
  File "C:\Users\suraj\PycharmProjects\PythonProject\.venv\Lib\site-packages\customtkinter\windows\ctk_tk.py", line 165, in mainloop
    super().mainloop(*args, **kwargs)
    ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
  File "C:\Users\suraj\AppData\Local\Programs\Python\Python313\Lib\tkinter\__init__.py", line 1599, in mainloop
    self.tk.mainloop(n)
    ~~~~~~~~~~~~~~~~^^^
  File "C:\Users\suraj\AppData\Local\Programs\Python\Python313\Lib\tkinter\__init__.py", line 2063, in __call__
    def __call__(self, *args):
    
KeyboardInterrupt

Process finished with exit code -1

I even tried adding a specific 'Exit' button (self.exitbutton) on the login window with an 'exit' function, seen in the code just before if __name__ == "__main__" but it does not stop the issue. Edited the post to include the exit code I had missed in case relevant.

8
  • It work for me. Using Python 3.13.3, Windows 10 Commented May 22 at 11:59
  • show_main_window() should place after def __init__(): Commented May 22 at 12:15
  • Shifted show_main_window(), I am also running Python 3.13.3 but on Windows 11, I copied this very code into a fresh python project but I am still getting the error and have to stop the code manually on Pycharm by clicking the button twice Commented May 22 at 13:12
  • You need to update pyCharm Commented May 22 at 13:13
  • I am using the PyCharm 2025.1.1.1 version which as far as I can see is the latest edition, could it be Windows 11 or customtkinter itself causing issues? Commented May 22 at 13:16

2 Answers 2

2

From the documentation:

During the runtime of a program there should only be one instance of this class with a single call of the .mainloop() method, which starts the app. Additional windows are created using the CTkToplevel class.

You violate this multiple times in your code:

  • First you create a LoginWindow instance which creates a CTk instance and start its .mainloop() method with app.run() (so far this is fine).
  • Then you create a second CTk instance in .show_main_window() and execute its .mainloop() as well, when you should use CTkToplevel without .mainloop().
  • Finally, in MainFrame.logout(), you create yet another LoginWindow instance when you should restore the original one with .deiconify(). This requires you to pass the original LoginWindow instance to your MainFrame instance, such that you can reference it inside .logout().

I'm not 100% sure that this causes the error, but it looks like the most likely cause to me, especially since I don't get any error if I click the exit button before loggin in.

Sign up to request clarification or add additional context in comments.

Comments

1

@Aemyl is correct. Your problem is orphaned instances of Tk.

  1. First you instantiate Tk here: self.window = ctk.CTk()
  2. Then you do this in submit:
self.window.withdraw()  # hides the window
self.window.quit()  # exits the mainloop, but the instance is still live
print(self.entrypassword.get())  # add this line and you can see that the widgets are still accessible
  1. Then in show_main_window you start another instance of Tk: window = ctk.CTk(). Remember, though, that the first instance is still there.
  2. In logout, you correctly kill the new instance: self.master.destroy. Again, first instance is still live. You just killed the second one.
  3. Then you create a new instance of LoginWindow, which starts another instance of Tk. But the old instance is still there, orphaned, because you never killed it. You just exited the mainloop.

Solution 1 - You actually want new instances

Easy fix. Just replace

self.window.withdraw()
self.window.quit()

with

self.window.destroy()  # no more orphaned instance

Solution 2 - You want to reuse the first instance

  1. Replace
self.window.withdraw()
self.window.quit()

with

self.window.withdraw()
self.user_input.set('')  # clear the Entry
  1. Use Toplevel in show_main_window:
  • Replace window = ctk.CTk() with window = ctk.CTkToplevel()
  • Remove this line: window.mainloop()
  1. In logout, replace
login = LoginWindow()
login.run()

with

self.master.master.deiconify()
  1. You'll need to handle closing the second window without invoking logout, though, or you'll still have that hidden window hanging around if you close with the [X] button. Add this line just after creating the Toplevel window (in show_main_window:
window.protocol('WM_DELETE_WINDOW', self.exit)

I don't know how you're structuring your application, but either solution should fix the immediate issue.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.