Python类 - 从父类继承属性到顶层

Posted

技术标签:

【中文标题】Python类 - 从父类继承属性到顶层【英文标题】:Python class - inherit attribute from parent class to toplevel 【发布时间】:2021-01-25 17:33:29 【问题描述】:

我正在尝试使用 OOP 方法来创建从父类继承到***的类。我想从Window1Window2 类中获取self.txtofName。但它引发了“AttributeError:类型对象'Window1'没有属性'txtofName'”。谁能帮帮我?

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

完整的追溯:

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'

【问题讨论】:

用你自己的话说,当你写class Window2(Window1):时,它的目的是什么? 【参考方案1】:

嗨,james,我认为问题在于让 Windows2 类继承 Windows1 类是错误的。我做了一些改变,比如

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)

在windows2中注意到我们声明geometry、config、title为self,这里self是新窗口,self.parent是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')

最重要的是

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

这里有完整的故事,试试看。

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

【讨论】:

【参考方案2】:

按照这些步骤操作

不要做 app = Window1(root) 因为你已经继承了Window2中的Window1

所以,在Window2中使用super进行初始化

super().__init__(master)

现在你可以为 Window1 做任何事情了, 为按钮分配命令 self.btnNext.config(command=self.new_window_pop)

现在为 TopLevel Window 创建一个方法:

这是您的完整代码:

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')
        self.btnNext.grid(row=6, column=1, sticky=E)


class Window2(Window1):
    def __init__(self, master):
        super().__init__(master)
        self.btnNext.config(command=self.new_window_pop)

    def new_window_pop(self):
        self.master = Toplevel(self.master)
        self.master.geometry = '1350x750+0+0'
        self.master.config(bg='powder blue')
        self.master.title('User Information and Payment')

        self.ftitle = Frame(self.master, bd=10, width=1350, bg='powder blue', relief=RIDGE, padx=20)
        self.ftitle.grid(columnspan=3, column=0, row=0)
        self.ftitle2 = Frame(self.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(self.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(self.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 = self.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 = Window2(root)
    root.mainloop()


if __name__ == '__main__':
    main()

如果您需要任何解释,请在评论中提问。

【讨论】:

以上是关于Python类 - 从父类继承属性到顶层的主要内容,如果未能解决你的问题,请参考以下文章

无法查看从父类继承的属性 [重复]

java子类从父类继承某个属性,怎么添加特定的注解不影响父类

Dart - 从父类方法访问继承的静态属性的方法

Python_12 多继承与多态

python面向对象之继承

子类从父类继承过来的方法可以操作子类自己定义的成员变量吗