如何组织tkinter申请?

First of all, I am sorry if this sounds like a question that's been asked before, and I am following Bryan Oakley's answer to this post Best way to structure a tkinter application?, which is quite instructive. However, it does leave out a few details that if present, a novice like me would find very helpful. Below is how I have currently structured my application (a tiny version of it), which consists of a main app, with several tabs (using ttk.Notebook), and each tab contains several frames and in each frame I have multiple widgets. You can see that it makes no sense to have all that code in the body of my main app. I would like to (at least) create a class for each tab (Tabj) and place the code in tabj.py file.

import tkinter as tk
from tkinter import ttk, N, S, END, EXTENDED

class MainApplication(tk.Frame):
    def __init__(self, root, *args, **kwargs):
        tk.Frame.__init__(self, root, *args, **kwargs)
        self.root = root
        self.nb = ttk.Notebook(root)

        self.tab1 = ttk.Frame(self.nb)
        self.tab2 = ttk.Frame(self.nb)

        self.nb.add(self.tab1, text='TAB1')
        self.nb.add(self.tab2, text='TAB2')

        self.nb.grid(row=0, column=0)

        #contents of tab1 - which I would like to place in their own class
        self.frame = tk.Frame(self.tab1)
        self.frame.grid(row=0, column=0)

        self.button = tk.Button(self.frame, text='Hello', command=self.say_hello)
        self.button.grid(row=0, column=0)

        self.items = ['A','B','C']

        self.listbox = tk.Listbox(self.frame, selectmode=EXTENDED, exportselection=0)
        self.listbox.grid(row=1, column=0)

        self.scrollbar = tk.Scrollbar(self.frame, orient='vertical')
        self.scrollbar.grid(row=1, column=1, sticky=N+S)
        self.listbox.config(yscrollcommand=self.scrollbar.set)
        self.scrollbar.config(command=self.listbox.yview)
        self.listbox.bind('<<ListboxSelect>>', self.get_item)

        for item in self.items:
            self.listbox.insert(END, item) 


        #contents of tab2 - which should be in their own class
        #...
        #...


    def say_hello(self):
        print('hello')

    def get_item(self, evt):
        w = evt.widget
        index = int(w.curselection()[0])
        print('item selected = {}'.format(self.items[index]))

if __name__ == "__main__":
    root = tk.Tk() 
    MainApplication(root)
    root.mainloop()

问题:

  • 一旦我在tab1.py文件中创建了一个Tab1类,并将其导入到我的主应用程序中(从tab1导入Tab1导入),我究竟该如何访问say_hello方法?我是否将此方法保留在主应用程序的主体中(并在我的tab1.py文件中包含此方法的导入语句),还是将该方法移到tab1.py文件中,还是创建一个全新的文件? py文件,并在该文件中放置方法?
  • 如何处理列表框与项目选择之类的事件的绑定?同样,我的许多列表框都绑定到某些事件,并且所调用的功能全部在我的主应用程序主体中。一旦为不同的选项卡创建了单独的类,我就对这些功能真正属于什么感到困惑。
  • 我是否将方法say_hello和get_item留在应用程序主体中?我在其他选项卡中确实有可访问这些相同方法的小部件。我应该为这些方法创建一个全新的.py文件吗?如果是这样,每个选项卡中的小部件将如何访问这些功能?
  • 一个相关的问题:我有很多带有附加滚动条的列表框。在一个单独的文件中包含一个用于创建通用列表框的函数是否有意义?这个函数会有return语句吗? (例如lb = tk.Listbox(...)返回lb?)lb.grid()也会在此函数内吗?

现在,我的应用程序可以完全满足我的要求,但是我知道我的代码结构不正确(设计)。我不想在我的应用程序主体中滚动数百行代码。一旦将代码分为不同的类,我真的需要帮助来了解某些回调函数所属的位置。如果将窗口小部件事件绑定到一个函数,那么该函数是否与窗口小部件所驻留的类相同?我知道我的困惑很大一部分是由于我对OO编程缺乏了解,尽管一小部分特别是与tkinter有关。任何帮助表示赞赏。如果不清楚我要做什么,请发表评论,我可以澄清。提前致谢。

评论