当前位置: 首页 > 知识库问答 >
问题:

创建从一个类到另一个类的变量

柳珂
2023-03-14

我目前正在与tkinter一起完成一项学校作业,为用户创建一个图形用户界面以输入他们的输入。我决定将输入分成不同的页面,以避免用户被问题淹没,并且不需要滚动
每一页都有一系列标签和条目,在一个右除数和一个左除数上分开,我已经设法在每一页上实现了这一点,付出了一些努力。这是我工作代码的简化版本:

import tkinter as tk


class Layers(tk.Frame):
    def __init__(self, root):
        super().__init__(root)

        self.layers = []

        self.layers.append(Welcome_Page(self))
        self.layers.append(Form_1(self))
        self.layers.append(Form_2(self))

        for layer in self.layers:
            layer.add_form(self)
            layer.add_buttons(self)
            layer.grid(row=0, column=0, sticky="nsew")

        self.layers[0].tkraise()


class Welcome_Page(tk.Frame):
    def __init__(self, root):
        super().__init__(root, width=600, height=800, background="red")

    def add_buttons(self, root):
        self.next = tk.Button(self, text="Next page", width=25, height=5, command=self.master.layers[1].tkraise)
        self.next.place(relx=1, rely=1, anchor="se")

        self.prev = tk.Button(self, text="Quit", width=25, height=5, command=self.master.master.destroy)
        self.prev.place(relx=0, rely=1, anchor="sw")
        pass

    def add_form(self, root):
        self.text_label = tk.Label(self, text="Welcome to this program")
        self.text_label.place(relx=0.5, rely=0, anchor="n")
        pass



class Form_1(tk.Frame):
    def __init__(self, root):
        super().__init__(root, width=600, height=800, background="yellow")

    def add_buttons(self, root):
        self.next = tk.Button(self, text="Next page", width=25, height=5, command=self.master.layers[2].tkraise)
        self.next.place(relx=1, rely=1, anchor="se")

        self.prev = tk.Button(self, text="Back", width=25, height=5, command=self.master.layers[0].tkraise)
        self.prev.place(relx=0, rely=1, anchor="sw")
        pass

    def add_form(self, root):
        self.text_label = tk.Label(self, text="Personal data")
        self.text_label.place(relx=0.5, rely=0, anchor="n")

        self.container_left = tk.Frame(self, background="#BAFFCE")
        self.container_right = tk.Frame(self, background="#72FF9A")
        self.container_left.grid(row=0, column=0, sticky="nsew")
        self.container_right.grid(row=0, column=1, sticky="nsew")
        self.grid_columnconfigure(0, weight=1, uniform="group1")
        self.grid_columnconfigure(1, weight=1, uniform="group1")
        self.grid_rowconfigure(0, weight=1)

        self.last_name_label = tk.Label(self.container_right, text="Last name")
        self.last_name_space = tk.Entry(self.container_right, text="lastname")
        self.last_name_label.grid(row=0, column=0, padx=(10,0), pady=(10,0))
        self.last_name_space.grid(row=0, column=1, padx=(5, 0), pady=(10,0))

        pass


class Form_2(tk.Frame):
    def __init__(self, root):
        super().__init__(root, width=600, height=800, background="gray")

    def add_buttons(self, root):
        self.next = tk.Button(self, text="Next page", width=25, height=5)
        self.next.place(relx=1, rely=1, anchor="se")

        self.prev = tk.Button(self, text="Back", width=25, height=5, command=self.master.layers[1].tkraise)
        self.prev.place(relx=0, rely=1, anchor="sw")
        pass

    def add_form(self, root):
        self.text_label = tk.Label(self, text="Third page")
        self.text_label.place(relx=0.5, rely=0, anchor="n")
        pass


if __name__ == '__main__':
    root = tk.Tk()
    root.geometry("600x800")

    window = Layers(root)
    window.pack(expand=True, fill="both")
    root.mainloop()

然而,在将每个页面拆分为两个不同的Frame()容器时,我遇到了两个问题:

  • 用ipadx和ipady设置框架的内部填充似乎没有任何作用。不过,我已经用padx和pady手动设置了它里面的每个元素的位置,这很好,但是我相信我应该能够在container_left和container_right上使用内部填充。
  • 为每个页面设置容器是多余的,因为它们都将被分成两个框架。我已经尝试了以下方法,但它并不像我预期的那样工作(一点也不)。
class Layers(tk.Frame):
    def __init__(self, root):
        super().__init__(root)

        self.layers = []

        self.layers.append(Welcome_Page(self))
        self.layers.append(Form_1(self))
        self.layers.append(Form_2(self))

        for layer in self.layers:
            layer.add_form(self)
            layer.add_buttons(self)
            layer.grid(row=0, column=0, sticky="nsew")

            layer.container_left = tk.Frame(layer, background="#BAFFCE")
            layer.container_right = tk.Frame(layer, background="#72FF9A")
            layer.container_left.grid(row=0, column=0, sticky="nsew")
            layer.container_right.grid(row=0, column=1, sticky="nsew")
            layer.grid_columnconfigure(0, weight=1, uniform="group1")
            layer.grid_columnconfigure(1, weight=1, uniform="group1")
            layer.grid_rowconfigure(0, weight=1)

            print(layer)

        self.layers[0].tkraise()

我得到的错误是AttributeError:“Form\u 1”对象没有属性“container\u right”。我从中得到的是,我没有在类中创建变量,而是在其他地方创建变量,尽管我使用的是。如何在不重用代码的情况下在类内部创建变量?

任何其他建议也很受欢迎,因为我对Python和Tkinter相当陌生。


共有2个答案

公西英叡
2023-03-14

我知道您提到希望保持类结构不变,但为表单页面引入超类可能是值得的。从那里,您可以定义add_formadd_按钮实例方法,只需从超类的\uuuuu init\uuuu内部调用它们,而不必在页面中循环。比如说:

class FormPage(tk.Frame):
    def __init__(self, parent):
        tk.Frame.__init__(self, parent, width=600, height=800, background="yellow")
        self.parent=parent
    
        self.add_buttons()
        self.add_form()

    def add_buttons(self):
        self.next = tk.Button(self, text="Next page", width=25, height=5)
        self.next.place(relx=1, rely=1, anchor="se")

        self.prev = tk.Button(self, text="Back", width=25, height=5)
        self.prev.place(relx=0, rely=1, anchor="sw")

    def add_form(self):
        self.text_label = tk.Label(self) #use the configure method in child classes to set the text
        self.text_label.place(relx=0.5, rely=0, anchor="n")

        self.container_left = tk.Frame(self, background="#BAFFCE")
        self.container_right = tk.Frame(self, background="#72FF9A")
        self.container_left.grid(row=0, column=0, sticky="nsew")
        self.container_right.grid(row=0, column=1, sticky="nsew")
        self.grid_columnconfigure(0, weight=1, uniform="group1")
        self.grid_columnconfigure(1, weight=1, uniform="group1")
        self.grid_rowconfigure(0, weight=1)

因此,FormPage的初始化将在实例化表单页面时自动调用add_按钮add_表单方法。然后,对于特定表单,您可以执行以下操作:

class Form_1(FormPage):
    def __init__(self, parent):
        tk.Frame.__init__(parent) #call FormPage's initialisation

    def add_buttons(self):
        self.next.configure(command=self.parent.layers[1].tkraise)
        ...#add the specific functionality of the buttons using configure
    
    def add_form(self):
        super().add_form()
        self.text_Label.configure(text="Personal Information")

        self.last_name_label = tk.Label(self.container_right, text="Last name")
        self.last_name_space = tk.Entry(self.container_right, text="lastname")
        self.last_name_label.grid(row=0, column=0, padx=(10,0), pady=(10,0))
        self.last_name_space.grid(row=0, column=1, padx=(5, 0), pady=(10,0))

因此,FormPage的任何子级都具有container\u leftcontainer\u right属性。然后,如果某些表单需要更多按钮,您可以在该表单的类中重写方法add\u buttons。对于任何其他方法也是如此。然后,您只需要一个地方来存储所有页面,比如类。在我看来,你不需要把所有的图层都放在一个网格上,因为你将从导航按钮调用tkraise。我认为您的类可以缩减为:

class Layers(tk.Tk):
    def __init__(self):
        super().__init__(self)

        self.layers = []

        for F in {Welcome_Page, Form_1, Form_2}:
            self.layers.append(F(self))

        self.layers[0].tkraise()

一般来说,继承层次结构是减少代码重复的好方法。希望这有帮助:)

蔡弘扬
2023-03-14

通过将第17行更改为:

layer.grid(row=0, column=0, sticky="nsew", ipadx=30, ipady=30,)
 类似资料:
  • 我已经阅读了很多stackoverflow的页面,但是我无法将我的ArrayList复制到另一个类中。下面是一个场景,我正在构建一个快速的图书储蓄应用程序,类似于图书馆中的应用程序,但更简单(用于学校)。 我有我的主库类(带有main),它为主菜单/选项设置了swing。 我有一个带有新书构造函数的book类,如下所示: 在这个类中,我在确认按钮上添加了一个,以确认上要作为对象添加的输入,如下所示

  • 我有两个Java类,Product和ProductReview。ProductReview除了变量long id和String review外,还有一个名为Product的变量,该变量应包含类Product中的一个对象。例子: Products类有私有变量long id、String name和List评论(它也从Product评论类中获取评论)。产品类与Product评论有一对多的关联,反之亦然

  • 我正在做一个新的项目,我试图建立一个货币系统,在那里我可以提取它,以转移到另一个变量(在另一个类)。我在解决这个问题上遇到了一些问题,我对如何编写代码感到非常失望。下面是我想链接的类(我想让“coinsamount”在我做/存款时进入类2“amount” 第2类:

  • 问题内容: 我想将一个类变量传递给另一个类,并使其成为该类的类变量。在以下情况下我该怎么做? 问题答案: 很难理解您正在问的问题,但这是一个可能的答案: 使B类成为A的子类: 如果重新声明为,则会出现一种情况,其中存在一个可以称为或的属性。(或在任一或刚刚…甚至作为或地方,并有类型和分别。) 如果您无法在和(或,以及一些包含声明的第三类)之间创建直接或子类型关系,那么您很不走运。他们无法共享声明。

  • 问题内容: 用Java开发一个简单的井字游戏。 我有一个名为的课程。此类应包含有用的游戏方法。游戏发生在另一个班级。 中的方法是。该方法应该将所有9个按钮(井字游戏板)上的文本设置为空白,再次将它们设置为启用,然后将变量设置为1。 这是它的代码: 是游戏主类中的JButtons数组。 该方法以前在游戏的主要类中使用。但是现在它在不同的类中,它无法到达该类中的按钮并对其进行操作。 我在中创建了get

  • 我是一名Java程序员初学者。我试图在类交通中访问类车中的两个列表,这样我就可以执行while循环,循环直到主类中的列表为空 这就是我现在掌握的代码,我试着从普通车上扩展流量,但没有成功,我被卡住了。我该怎么解决这个问题?