Search code examples
pythoninheritancetkintertoplevelpython-class

Python class - inherit attribute from parent class to toplevel


I am trying to use OOP approach to create class that inherit from Parent class to top-level. I want to get the self.txtofName from Window1 to Window2 class. But it raises an "AttributeError: type object 'Window1' has no attribute 'txtofName'". Can anyone help me?

from tkinter import *
from PIL import Image, ImageTk
import time
from tkinter import ttk

class Window1(object):
    def __init__(self, master):
        self.master = master
        self.master.geometry = ('1600x750+0+0')
        self.master.config(bg='powder blue')
        self.master.title('ALVO HOTEL')
        
        # ==========Framing============
        self.ftop = Frame(master, width=1600, height=100, bg='powder blue', relief=RIDGE, pady=20)
        self.ftop.grid(columnspan=3, column=0, row=0)
        self.f1 = Frame(master,width=800,height=700,relief=SUNKEN, bg='powder blue', pady=50, bd=3)
        self.f1.grid(column=1, row=2, sticky="nsew")
        self.f4 = Frame(master, width=100, height=700, relief=SUNKEN, bg='powder blue', pady=50, padx=20, bd=3)
        self.f4.grid(column=2, row=2, sticky="nsew")


        self.labelofName = Label(self.f1, font=('arial', 16, 'bold'), text='Name: ', bg='powder blue', bd=10, anchor=W)
        self.labelofName.grid(row=0, column=0, pady=(20, 10))
        self.txtofName = Entry(self.f1, font=('arial', 16, 'bold'), bd=10, insertwidth=4, bg='white', justify='left')
        self.txtofName.grid(row=0, column=1, pady=(20, 10))

        self.btnNext = Button(self.f1, padx=10, pady=8, bd=10, fg='white', font=('arial', 10, 'bold'), width=10, text='Next Page', bg='green', command=self.new_window_pop)
        self.btnNext.grid(row=6, column=1, sticky=E)
        
    def new_window_pop(self):
        Window2(Toplevel(self.master))


class Window2(Window1):
    def __init__(self, master):
        self.master = master
        self.master.geometry = ('1350x750+0+0')
        self.master.config(bg='powder blue')
        self.master.title('User Information and Payment')

        self.ftitle = Frame(master, bd=10, width=1350, bg='powder blue', relief=RIDGE, padx=20)
        self.ftitle.grid(columnspan=3, column=0, row=0)
        self.ftitle2 = Frame(master, bd=10, width=1350, height=100, bg='powder blue', relief=RIDGE, padx=20)
        self.ftitle2.grid(columnspan=3, column=0, row=3, pady=(0,20))
        self.fbutton = Frame(master, width=1350, height=50, bg='powder blue', relief=RIDGE, padx=10, pady=20)
        self.fbutton.grid(columnspan=3, column=0, row=2)
        self.finfomain = Frame(master, bd=10, width=1350, height=400, bg='powder blue', relief=RIDGE)
        self.finfomain.grid(columnspan=3, column=0, row=1)

        self.finfo1 = Frame(self.finfomain, bd=5, width=900, height=300, bg='powder blue', relief=RIDGE, padx=10)
        self.finfo1.grid(column=0, row=0)
        self.finfo1a = Frame(self.finfomain, bd=5, width=900, height=100, bg='powder blue', relief=RIDGE, padx=20)
        self.finfo1a.grid(column=0, row=1)
        self.finfo2 = Frame(self.finfomain, bd=5, width=450, height=400, bg='powder blue', relief=RIDGE, padx=20)
        self.finfo2.grid(column=1, row=0, rowspan=2)

        name = Window1.txtofName.get()
        self.FirstName = StringVar()

        self.lblfirstname = Label(self.finfo1, font=('arial', 16, 'bold'), bg='powderblue', text='First Name:', padx=2)
        self.lblfirstname.grid(row=0, column=0, sticky=W)
        self.txtfirstfname = Entry(self.finfo1, font=('arial', 16, 'bold'), textvariable=self.FirstName, bd=3, insertwidth=5, bg='white', justify='left')
        self.txtfirstfname.grid(row=0, column=1)
        
def main():
    root = Tk()
    app = Window1(root)
    root.mainloop()

if __name__ == '__main__':
    main()

Full traceback:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Python\Python385\lib\tkinter\__init__.py", line 1883, in __call__
    return self.func(*args)
  File "d:/Code/Cpet5/new.py", line 31, in new_window_pop
    Window2(Toplevel(self.master))
  File "d:/Code/Cpet5/new.py", line 57, in __init__
    name = Window1.txtofName.get()
AttributeError: type object 'Window1' has no attribute 'txtofName'

Solution

  • hi james I think that the problem is that that you’re wrong to let the Windows2 class inherit the Windows1 class. I've made some changes like

    def new_window_pop(self):
            #avoid declaring the class type here
            #Window2(Toplevel(self.master))
            #and pass self because you can thought to self as master...
            Window2(self)
    

    and in the windows2 notice that we declare geometry, config, title as self, here self is the new windows, and self.parent is window1

    #declare class type directly...
    
    class Window2(Toplevel):
        def __init__(self, parent):
        super().__init__()
    
        #Windows2 recive a parent....
        self.parent = parent
        self.geometry = ('1350x750+0+0')
        self.config(bg='powder blue')
        self.title('User Information and Payment')
    

    and above all

     #here the reference is wrong
        #name = Window1.txtofName.get()
        #the right reference is self.parent....
        name = self.parent.txtofName.get()
        self.FirstName = StringVar()
        #here, if you need to use the textvariable you must first assign it
        self.FirstName.set(name)
    

    here the full story, try it.

    from tkinter import *
    from PIL import Image, ImageTk
    import time
    from tkinter import ttk
    
    class Window1(object):
        def __init__(self, master):
            self.master = master
            self.master.geometry = ('1600x750+0+0')
            self.master.config(bg='powder blue')
            self.master.title('ALVO HOTEL')
            
            # ==========Framing============
            self.ftop = Frame(master, width=1600, height=100, bg='powder blue', relief=RIDGE, pady=20)
            self.ftop.grid(columnspan=3, column=0, row=0)
            self.f1 = Frame(master,width=800,height=700,relief=SUNKEN, bg='powder blue', pady=50, bd=3)
            self.f1.grid(column=1, row=2, sticky="nsew")
            self.f4 = Frame(master, width=100, height=700, relief=SUNKEN, bg='powder blue', pady=50, padx=20, bd=3)
            self.f4.grid(column=2, row=2, sticky="nsew")
    
    
            self.labelofName = Label(self.f1, font=('arial', 16, 'bold'), text='Name: ', bg='powder blue', bd=10, anchor=W)
            self.labelofName.grid(row=0, column=0, pady=(20, 10))
            self.txtofName = Entry(self.f1, font=('arial', 16, 'bold'), bd=10, insertwidth=4, bg='white', justify='left')
            self.txtofName.grid(row=0, column=1, pady=(20, 10))
    
            self.btnNext = Button(self.f1, padx=10, pady=8, bd=10, fg='white', font=('arial', 10, 'bold'), width=10, text='Next Page', bg='green', command=self.new_window_pop)
            self.btnNext.grid(row=6, column=1, sticky=E)
            
        def new_window_pop(self):
            #avoid declaring the class type here
            #Window2(Toplevel(self.master))
            #and pass self...self = master
            Window2(self)
    
    #declare class type directly...
    class Window2(Toplevel):
        def __init__(self, parent):
            super().__init__()
    
            #Windows2 recive a parent....
            self.parent = parent
            self.geometry = ('1350x750+0+0')
            self.config(bg='powder blue')
            self.title('User Information and Payment')
    
            #notice this Frame(self,....
            self.ftitle = Frame(self, bd=10, width=1350, bg='powder blue', relief=RIDGE, padx=20)
            self.ftitle.grid(columnspan=3, column=0, row=0)
            self.ftitle2 = Frame(self, bd=10, width=1350, height=100, bg='powder blue', relief=RIDGE, padx=20)
            self.ftitle2.grid(columnspan=3, column=0, row=3, pady=(0,20))
            self.fbutton = Frame(self, width=1350, height=50, bg='powder blue', relief=RIDGE, padx=10, pady=20)
            self.fbutton.grid(columnspan=3, column=0, row=2)
            self.finfomain = Frame(self, bd=10, width=1350, height=400, bg='powder blue', relief=RIDGE)
            self.finfomain.grid(columnspan=3, column=0, row=1)
    
            self.finfo1 = Frame(self.finfomain, bd=5, width=900, height=300, bg='powder blue', relief=RIDGE, padx=10)
            self.finfo1.grid(column=0, row=0)
            self.finfo1a = Frame(self.finfomain, bd=5, width=900, height=100, bg='powder blue', relief=RIDGE, padx=20)
            self.finfo1a.grid(column=0, row=1)
            self.finfo2 = Frame(self.finfomain, bd=5, width=450, height=400, bg='powder blue', relief=RIDGE, padx=20)
            self.finfo2.grid(column=1, row=0, rowspan=2)
    
            #here the reference is wrong
            #name = Window1.txtofName.get()
            #the right reference is self.parent....
            name = self.parent.txtofName.get()
            self.FirstName = StringVar()
            #here, if you need to use the textvariable you must first assign it
            self.FirstName.set(name)
    
            self.lblfirstname = Label(self.finfo1, font=('arial', 16, 'bold'), bg='powderblue', text='First Name:', padx=2)
            self.lblfirstname.grid(row=0, column=0, sticky=W)
            self.txtfirstfname = Entry(self.finfo1, font=('arial', 16, 'bold'), textvariable=self.FirstName, bd=3, insertwidth=5, bg='white', justify='left')
            self.txtfirstfname.grid(row=0, column=1)
    
            
            
    def main():
        root = Tk()
        app = Window1(root)
        root.mainloop()
    
    if __name__ == '__main__':
        main()