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.
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:
LoginWindow instance which creates a CTk instance and start its .mainloop() method with app.run() (so far this is fine).CTk instance in .show_main_window() and execute its .mainloop() as well, when you should use CTkToplevel without .mainloop().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.
@Aemyl is correct. Your problem is orphaned instances of Tk.
self.window = ctk.CTk()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
show_main_window you start another instance of Tk: window = ctk.CTk(). Remember, though, that the first instance is still there.logout, you correctly kill the new instance: self.master.destroy. Again, first instance is still live. You just killed the second one.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.Easy fix. Just replace
self.window.withdraw()
self.window.quit()
with
self.window.destroy() # no more orphaned instance
self.window.withdraw()
self.window.quit()
with
self.window.withdraw()
self.user_input.set('') # clear the Entry
Toplevel in show_main_window:window = ctk.CTk() with window = ctk.CTkToplevel()window.mainloop()logout, replacelogin = LoginWindow()
login.run()
with
self.master.master.deiconify()
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With