Lauk-k
Lauk-k

Reputation: 90

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...

Upvotes: 2

Views: 409

Answers (3)

Parfait
Parfait

Reputation: 107577

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()

Upvotes: 2

Mike - SMT
Mike - SMT

Reputation: 15226

I do not agree with the method of how you are invoking your 2nd python file. You really dont need to use exec here.

However if you really want to you need to add import tkinter.ttk as ttk to your first page for it to work right.

Your best option is to import the 2nd file on the 1st file and invoke it by calling the class name.

so for you imports on the first page you need to add import BatchFrame.

Then call it in your code.

Replace:

exec(open("./test2.py").read())

with:

BatchFrame.BatchFrame(root)

I do see one mistake in your BatchFrame class thought.

change this:

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

to this:

self.label_photo = Label(master, image=self.photo)

UPDATE: To address your issue from the comment make these changes:

1: Add this to your BatchFrame Class:

class BatchFrame(Frame):
    def __init__(self, master):
        super().__init__(master)
        self.master = master # add this
        self.master.title("SBSHREG") # and this
        self.master.geometry("432x480") # and this

2: Remove this from your BatchFrame file:

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

3: Add this to your LoginFrame class:

class LoginFrame(Frame):
    def __init__(self, master):
        super().__init__(master)
        self.master = master # add this

4: In the LoginFrame class change this:

BatchFrame.BatchFrame(root)

to this:

BatchFrame.BatchFrame(self.master)

Upvotes: 1

Ron Norris
Ron Norris

Reputation: 2690

I recommend importing batchframe instead of executing it.

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

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

        self.label_username = Label(self, text="Username")
        self.label_password = Label(self, text="Password")
        self.photo = PhotoImage(file="icon.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()
            # Create the instance of the BatchFrame class, passing in self.master
            self.batchframe = BatchFrame(self.master)
        else:
            tm.showerror("SBSHREG", "Incorrect username")

Then in batchframe.py change variable reference from root to master

Upvotes: 0

Related Questions