将对象传递到类实例内的选项卡中

时间:2018-08-03 18:21:05

标签: python tkinter

我一直在努力学习OOP。我知道对象可以是类的实例。类具有参数和方法,就像创建对象的“对象构造函数”一样。我正在重新组织第一个项目中的代码,以使任何可能的内容都可以成为类的一部分。现在,我正在使用GUI,但是在理解使用类构造GUI的过程时遇到了麻烦。特别是在类内部具有选项卡,并在每个选项卡中添加对象。

这是我的代码当前外观的一个示例:

import tkinter
from tkinter import ttk


class Win:

    def __init__(self, master):
        nb = ttk.Notebook(master, width=390, height=470)
        nb.pack()

        tab = ttk.Frame(nb)
        nb.add(tab, text='title')

        tab2 = ttk.Frame(nb)
        nb.add(tab2, text='Graphs')

        tab3 = ttk.Frame(nb)
        nb.add(tab3, text='Messages')

        tab4 = ttk.Frame(nb)
        nb.add(tab4, text='Instructions')

        label = tkinter.Label(tab, text='text')
        label.grid(row=0, column=0, sticky=tkinter.N, pady=10)

        menu = tkinter.Menu(master, tearoff=False)
        master.config(menu=menu)
        subMenu = tkinter.Menu(menu, tearoff=False)
        menu.add_cascade(label="File", menu=subMenu)
        subMenu.add_separator()
        subMenu.add_command(label='Exit', command=master.destroy)

root = tkinter.Tk()
root.title("SC")
root.geometry('400x500')
root.resizable(width=False, height=False)

main_win = Win(root)

root.mainloop()

要将对象放在main_win中的每个标签中,该怎么办?我尝试将对象放在main_win下,然后在对象中传递参数main_win,但这似乎不起作用。我是否应该有一个用于制作标签的类,然后创建一个对象tab并将新对象传递到其中?

预先感谢您的帮助。无法在任何地方找到此特定答案。

1 个答案:

答案 0 :(得分:0)

此代码显示了一种向“笔记本”选项卡添加内容的方法。它实现了abarnert的一些建议以及我自己的一些想法。我将Notebook分离到了自己的类中,并将Tk根初始化代码移到了主GUI类中。

我并不是说这是做这些事情的最好方法,我只是在举例说明一些启发您的可能性。 ;)

import tkinter as tk
from tkinter import ttk

class GUI(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("SC")
        self.geometry('400x500')
        self.resizable(width=False, height=False)

        names = ['Title', 'Graphs', 'Messages', 'Instructions']
        self.nb = self.create_notebook(names)
        self.menu = self.create_menus()

        # We can also add items to the Notebook here
        tab = self.nb.tabs['Instructions']
        tk.Label(tab, text='You should\nread these\ninstructions').pack()

        self.mainloop()

    def create_notebook(self, names):
        nb = MyNotebook(self, names)
        nb.pack()

        def add_label(parent, text, row, column):
            label = tk.Label(parent, text=text)
            label.grid(row=row, column=column, sticky=tk.N, pady=10)
            return label

        # Add some labels to each tab
        tab = nb.tabs['Title']
        for i in range(3):
            add_label(tab, 't' + str(i), i, 0)

        tab = nb.tabs['Graphs']
        for i in range(3):
            add_label(tab, 'g' + str(i), 0, i)

        tab = nb.tabs['Messages']
        for i in range(3):
            add_label(tab, 'm' + str(i), i, i)

        return nb

    def create_menus(self):
        menu = tk.Menu(self, tearoff=False)
        self.config(menu=menu)
        subMenu = tk.Menu(menu, tearoff=False)
        menu.add_cascade(label="File", menu=subMenu)
        subMenu.add_separator()
        subMenu.add_command(label='Exit', command=self.destroy)
        return menu

class MyNotebook(ttk.Notebook):
    ''' A customised Notebook that remembers its tabs in a dictionary '''
    def __init__(self, master, names):
        super().__init__(master, width=390, height=470)

        # Create tabs & save them by name in a dictionary
        self.tabs = {}
        for name in names:
            self.tabs[name] = tab = ttk.Frame(self)
            self.add(tab, text=name)

GUI()

我将以GUI的不同方法来完成创建笔记本和菜单的大部分工作。我本可以将该代码放在GUI.__init__中,但是它采用模块化的方式在单独的方法中执行,因此可以阻止.__init__方法变大。

我已将“笔记本和菜单”另存为实例属性self.nbself.menu。这里并不是必须的,它们可以只是GUI.__init__的局部变量,例如nbmenus。但是,将它们存储为属性可以使它们从GUI的其他方法访问,当您向类中添加更多内容时,这可能是必需的。


如果您从父类派生一个类,例如子类没有,则从MyNotebook来的ttk.Notebook(或从GUI来的tk.Tk具有自己的__init__方法,那么当您创建子实例时,父级的__init__将自动被调用。但是,如果孩子有自己的__init__,则父__init__ 不会被自动呼叫。但是我们需要父__init__中的内容来完成MyNotebook的新实例,以便初始化从ttk.Notebook继承的内容。因此,MyNotebook.__init__进行了super调用来实现这一目标。

通常,如果子类未定义父类定义的方法,则在子实例上调用该方法时,将调用父类的版本。而且,如果子级确实重新定义了继承的方法,您通常会希望在同一阶段在子级方法内调用父级方法,通常使用super来做到这一点。 __init__有点特殊,因为通常在创建实例后会自动调用它来初始化实例。


这是一个不使用子类的简单版本。它在根窗口上还具有一个Button小部件,当您单击它时会打印一个字符串。

import tkinter as tk
from tkinter import ttk

class GUI:
    def __init__(self):
        root = tk.Tk()
        root.title("SC")
        root.geometry('400x500')
        root.resizable(width=False, height=False)

        names = ['Title', 'Graphs', 'Messages', 'Instructions']
        self.nb = self.create_notebook(root, names)
        self.menu = self.create_menus(root)

        # We can also add items to the Notebook here
        tab = self.nb.tabs['Instructions']
        tk.Label(tab, text='You should\nread these\ninstructions').pack()

        btn = tk.Button(root, text='Click', command=self.button_command)
        btn.pack()

        root.mainloop()

    def button_command(self):
        print('The button was clicked')

    def create_notebook(self, root, names):
        nb = ttk.Notebook(root, width=390, height=450)
        nb.pack()

        # Create tabs & save them by name in a dictionary
        nb.tabs = {}
        for name in names:
            nb.tabs[name] = tab = ttk.Frame(root)
            nb.add(tab, text=name)

        def add_label(parent, text, row, column):
            label = tk.Label(parent, text=text)
            label.grid(row=row, column=column, sticky=tk.N, pady=10)
            return label

        # Add some labels to each tab
        tab = nb.tabs['Title']
        for i in range(3):
            add_label(tab, 't' + str(i), i, 0)

        tab = nb.tabs['Graphs']
        for i in range(3):
            add_label(tab, 'g' + str(i), 0, i)

        tab = nb.tabs['Messages']
        for i in range(3):
            add_label(tab, 'm' + str(i), i, i)

        return nb

    def create_menus(self, root):
        menu = tk.Menu(root, tearoff=False)
        root.config(menu=menu)
        subMenu = tk.Menu(menu, tearoff=False)
        menu.add_cascade(label="File", menu=subMenu)
        subMenu.add_separator()
        subMenu.add_command(label='Exit', command=root.destroy)
        return menu

GUI()