Search code examples
pythonpython-3.xtkinterdestroyttk

Tkinter won't close correctly and launch new file


I made a little login screen. After I put in the credentials I want the Tkinter to be closed and open a new python file. If you execute the code below it will give me the error NameError: name ttk is not defined. In the other file I imported everything and gave it the correct name.

The file I use for the login:

from tkinter import *
import tkinter.messagebox as tm

class LoginFrame(Frame):
    def __init__(self, master):
        super().__init__(master)

        self.label_username = Label(self, text="Username")
        self.label_password = Label(self, text="Password")
        self.photo = PhotoImage(file="sbshreg.png")

        self.label_image = Label(root, image=self.photo)
        self.label_image.image = self.photo

        self.entry_username = Entry(self)
        self.entry_password = Entry(self, show="*")

        self.label_username.grid(row=0, sticky=E)
        self.label_password.grid(row=1, sticky=E)
        self.label_image.grid(row=3, column=2, rowspan=2, columnspan=2, sticky=W, padx=10)

        self.entry_username.grid(row=0, column=1, sticky=E)
        self.entry_password.grid(row=1, column=1, sticky=E)

        self.logbtn = Button(self, text="Login", command=self._login_btn_clicked)
        self.logbtn.grid(columnspan=2, column=1, row=2, sticky=S+E+N+W)

        self.grid()

    def _login_btn_clicked(self):
        username = self.entry_username.get()
        password = self.entry_password.get()

        if username == "123" and password == "123":
            tm.showinfo("SBSHREG", "Welcome 123")
            #The sweet spot where all goes wrong...
            self.destroy()
            exec(open("./BatchFrame.py").read())
        else:
            tm.showerror("SBSHREG", "Incorrect username")

root = Tk()
root.title("SBSHREG")
root.geometry("235x120")
lf = LoginFrame(root)
root.mainloop()

In the other file I got this: from tkinter import ttk as ttk which should prevent the error in the other file from happening.

from tkinter import *
import tkinter.messagebox as tm
from tkinter import ttk as ttk

class BatchFrame(Frame):
    def __init__(self, master):
        super().__init__(master)

        self.photo = PhotoImage(file="sbshreg.png")
        self.label_photo = Label(root, image=self.photo)
        self.label_photo.image = self.photo

        self.label_photo.grid(row=0, column=2, sticky=N, padx=10, pady=10)

        #Add frame starting here
        frame = LabelFrame(self.master, text='Voeg batch toe')
        frame.grid (row=0, column=0, padx=10)

        self.label_batch = Label(frame, text="Batchnummer")
        self.label_employee = Label(frame, text="Medewerker")
        self.label_material = Label(frame, text="Materiaalsoort")
        self.label_weight = Label(frame, text="Gewicht")

        self.entry_batch = Entry(frame)
        self.entry_employee = Entry(frame)
        self.entry_material= Entry(frame)
        self.entry_weight = Entry(frame)

        self.label_batch.grid(row=0, column=0, sticky=S+E+N+W, columnspan=2, padx=10)
        self.label_employee.grid(row=2, column=0,  sticky=S+E+N+W, columnspan=2, padx=10)
        self.label_material.grid(row=4, column=0,  sticky=S+E+N+W, columnspan=2, padx=10)
        self.label_weight.grid(row=6, column=0,  sticky=S+E+N+W, columnspan=2, padx=10)

        self.entry_batch.grid(row=1, column=0, sticky=S+E+N+W, columnspan=2, padx=10)
        self.entry_employee.grid(row=3, column=0, sticky=S+E+N+W, columnspan=2, padx=10)
        self.entry_material.grid(row=5, column=0, sticky=S+E+N+W, columnspan=2, padx=10)
        self.entry_weight.grid(row=7, column=0, sticky=S+E+N+W, columnspan=2, padx=10)

        self.btnadd = Button(frame, text='Voeg toe', command=self._btn_add_clicked)
        self.btnadd.grid(column=0, row=8, pady=10)

        #Search frame starting here
        framesearch = LabelFrame(self.master, text='Zoek')
        framesearch.grid(row=0, column=1, sticky=N)

        self.label_batch = Label(framesearch, text="Batchnummer")
        self.label_employee = Label(framesearch, text="Medewerker")

        self.entry_batch = Entry(framesearch)
        self.entry_employee = Entry(framesearch)

        self.label_batch.grid(row=0, column=0, sticky=S, columnspan=2, padx=10)
        self.label_employee.grid(row=2, column=0, sticky=S, columnspan=2, padx=10)

        self.entry_batch.grid(row=1, column=0, sticky=S + E + N + W, columnspan=2, padx=10, pady=10)
        self.entry_employee.grid(row=3, column=0, sticky=S + E + N + W, columnspan=2, padx=10, pady=10)

        self.btnbatch = Button(framesearch, text="Zoek", command=self._btn_batch_clicked)
        self.btnemployee = Button(framesearch, text="Zoek", command=self._btn_employee_clicked)

        self.btnbatch.grid(columnspan=1, column=2, row=1, sticky=W, padx=10)
        self.btnemployee.grid(columnspan=1, column=2, row=3, sticky=W, padx=10)

        #This is the viewingarea for the data
        self.tree = ttk.Treeview (height=10, columns=("Batchnummer", "Medewerker", "Materiaalsoort", "Gewicht"))
        self.tree.grid (row=9, columnspan=10, padx=10, pady=10)
        self.tree.heading('#1', text='Batchnummer', anchor=W)
        self.tree.heading('#2', text='Medewerker', anchor=W)
        self.tree.heading('#3', text='Materiaalsoort', anchor=W)
        self.tree.heading('#4', text='Gewicht', anchor=W)
        self.tree.column('#0', stretch=NO, minwidth=0, width=0)
        self.tree.column('#1', stretch=NO, minwidth=0, width=100)
        self.tree.column('#2', stretch=NO, minwidth=0, width=100)
        self.tree.column('#3', stretch=NO, minwidth=0, width=100)
        self.tree.column('#4', stretch=NO, minwidth=0, width=100)

        self.grid()

    def _btn_add_clicked(self):
        batch = self.entry_batch.get()

    def _btn_batch_clicked(self):
        batch = self.entry_batch.get()

    def _btn_employee_clicked(self):
        batch = self.entry_employee.get()


root = Tk()
root.title("SBSHREG")
root.geometry("432x480")
lf = BatchFrame(root)
root.mainloop()

If I change self.destroy() to root.destroy() I get the following error: _tkinter.TclError: can't invoke "label" command: application has been destroyed. In the second file the functions are not done yet because I'm still working on the file, but this shouldn't have any impact on the error.

I searched everywhere and tried a lot and I still got no clue whatsoever...


Solution

  • Consider initializing frames in a top level class, GUI, that handles opening of both frames where LoginFrame calls its parent's open_batch() (now lambda implemented) method. Below assumes LoginFrame.py and BatchFrame.py resides in same folder as GUI_App script.

    In this way, scripts run as standalone modules on one Tk() instance.

    GUIApp (calls child frames, LoginFrame, and BatchFrame)

    from tkinter import *
    import LoginFrame as LF
    import BatchFrame as BF
    
    class GUI():
    
        def __init__(self):    
            self.root = Tk()
            self.root.title("SBSHREG")
            self.root.geometry("235x120")
    
            self.root.open_batch = self.open_batch
    
            lf = LF.LoginFrame(self.root)
            self.root.mainloop()
    
        def open_batch(self):
            bf = BF.BatchFrame(self.root)
    
    app = GUI()
    

    LoginFrame

    from tkinter import *
    import tkinter.messagebox as tm
    
    class LoginFrame(Frame):
    
        def __init__(self, master):
            super().__init__(master)
    
            self.label_username = Label(self, text="Username")
            self.label_password = Label(self, text="Password")
            self.photo = PhotoImage(file="sbshreg.png")
    
            self.label_image = Label(self, image=self.photo)
            self.label_image.image = self.photo
    
            self.entry_username = Entry(self)
            self.entry_password = Entry(self, show="*")
    
            self.label_image.grid(row=0, column=2, rowspan=2, columnspan=2, sticky=W, padx=10)
            self.label_username.grid(row=2, sticky=E)
            self.label_password.grid(row=3, sticky=E)
    
            self.entry_username.grid(row=2, column=1, sticky=E)
            self.entry_password.grid(row=3, column=1, sticky=E)
    
            self.logbtn = Button(self, text="Login", command=lambda: self._login_btn_clicked(master))
            self.logbtn.grid(row=4, column=1, columnspan=2, sticky=S+E+N+W)
    
            self.grid()
    
        def _login_btn_clicked(self, controller):
            username = self.entry_username.get()
            password = self.entry_password.get()
    
            if username == "123" and password == "123":
                tm.showinfo("SBSHREG", "Welcome 123")
    
                self.destroy()
                controller.open_batch()
            else:
                tm.showerror("SBSHREG", "Incorrect username")
    

    BatchFrame

    from tkinter import *
    import tkinter.messagebox as tm
    from tkinter import ttk as ttk
    
    class BatchFrame(Frame):
    
        def __init__(self, master):
            super().__init__(master)    
    
            self.photo = PhotoImage(file="sbshreg.png")
            self.label_photo = Label(master, image=self.photo)
            self.label_photo.image = self.photo
    
            self.label_photo.grid(row=0, column=2, sticky=N, padx=10, pady=10)
    
            #Add frame starting here
            frame = LabelFrame(master, text='Voeg batch toe')
            frame.grid (row=0, column=0, padx=10)
    
            self.label_batch = Label(frame, text="Batchnummer")
            self.label_employee = Label(frame, text="Medewerker")
            self.label_material = Label(frame, text="Materiaalsoort")
            self.label_weight = Label(frame, text="Gewicht")
    
            self.entry_batch = Entry(frame)
            self.entry_employee = Entry(frame)
            self.entry_material= Entry(frame)
            self.entry_weight = Entry(frame)
    
            self.label_batch.grid(row=0, column=0, sticky=S+E+N+W, columnspan=2, padx=10)
            self.label_employee.grid(row=2, column=0,  sticky=S+E+N+W, columnspan=2, padx=10)
            self.label_material.grid(row=4, column=0,  sticky=S+E+N+W, columnspan=2, padx=10)
            self.label_weight.grid(row=6, column=0,  sticky=S+E+N+W, columnspan=2, padx=10)
    
            self.entry_batch.grid(row=1, column=0, sticky=S+E+N+W, columnspan=2, padx=10)
            self.entry_employee.grid(row=3, column=0, sticky=S+E+N+W, columnspan=2, padx=10)
            self.entry_material.grid(row=5, column=0, sticky=S+E+N+W, columnspan=2, padx=10)
            self.entry_weight.grid(row=7, column=0, sticky=S+E+N+W, columnspan=2, padx=10)
    
            self.btnadd = Button(frame, text='Voeg toe', command=self._btn_add_clicked)
            self.btnadd.grid(column=0, row=8, pady=10)
    
            #Search frame starting here
            framesearch = LabelFrame(master, text='Zoek')
            framesearch.grid(row=0, column=1, sticky=N)
    
            self.label_batch = Label(framesearch, text="Batchnummer")
            self.label_employee = Label(framesearch, text="Medewerker")
    
            self.entry_batch = Entry(framesearch)
            self.entry_employee = Entry(framesearch)
    
            self.label_batch.grid(row=0, column=0, sticky=S, columnspan=2, padx=10)
            self.label_employee.grid(row=2, column=0, sticky=S, columnspan=2, padx=10)
    
            self.entry_batch.grid(row=1, column=0, sticky=S + E + N + W, columnspan=2, padx=10, pady=10)
            self.entry_employee.grid(row=3, column=0, sticky=S + E + N + W, columnspan=2, padx=10, pady=10)
    
            self.btnbatch = Button(framesearch, text="Zoek", command=self._btn_batch_clicked)
            self.btnemployee = Button(framesearch, text="Zoek", command=self._btn_employee_clicked)
    
            self.btnbatch.grid(columnspan=1, column=2, row=1, sticky=W, padx=10)
            self.btnemployee.grid(columnspan=1, column=2, row=3, sticky=W, padx=10)
    
            #This is the viewingarea for the data
            self.tree = ttk.Treeview (height=10, columns=("Batchnummer", "Medewerker", "Materiaalsoort", "Gewicht"))
            self.tree.grid (row=9, columnspan=10, padx=10, pady=10)
            self.tree.heading('#1', text='Batchnummer', anchor=W)
            self.tree.heading('#2', text='Medewerker', anchor=W)
            self.tree.heading('#3', text='Materiaalsoort', anchor=W)
            self.tree.heading('#4', text='Gewicht', anchor=W)
            self.tree.column('#0', stretch=NO, minwidth=0, width=0)
            self.tree.column('#1', stretch=NO, minwidth=0, width=100)
            self.tree.column('#2', stretch=NO, minwidth=0, width=100)
            self.tree.column('#3', stretch=NO, minwidth=0, width=100)
            self.tree.column('#4', stretch=NO, minwidth=0, width=100)
    
            self.grid()
    
        def _btn_add_clicked(self):
            batch = self.entry_batch.get()
    
        def _btn_batch_clicked(self):
            batch = self.entry_batch.get()
    
        def _btn_employee_clicked(self):
            batch = self.entry_employee.get()