以下是我典型的python tkinter程序的整体结构。
def funA(): def funA1(): def funA12(): # stuff def funA2(): # stuff def funB(): def funB1(): # stuff def funB2(): # stuff def funC(): def funC1(): # stuff def funC2(): # stuff root = tk.Tk() button1 = tk.Button(root, command=funA) button1.pack() button2 = tk.Button(root, command=funB) button2.pack() button3 = tk.Button(root, command=funC) button3.pack()
funA funB当用户单击按钮 1、2、3 时,将弹出另一个带有小部件的 窗口funC。Toplevel
funA
funB
funC
Toplevel
我想知道这是否是编写 python tkinter 程序的正确方法?当然,即使我这样写也可以,但这是最好的方式吗?这听起来很愚蠢,但是当我看到其他人编写的代码时,他们的代码并没有被一堆函数弄乱,而且他们大多都有类。
有没有我们应该遵循的特定结构作为良好实践?在开始编写 python 程序之前我应该如何计划?
我知道编程中没有最佳实践这样的东西,我也没有要求它。我只是想要一些建议和解释,以使我在自己学习 Python 时保持正确的方向。
我提倡一种面向对象的方法。这是我开始使用的模板:
# Use Tkinter for python 2, tkinter for python 3 import tkinter as tk class MainApplication(tk.Frame): def __init__(self, parent, *args, **kwargs): tk.Frame.__init__(self, parent, *args, **kwargs) self.parent = parent <create the rest of your GUI here> if __name__ == "__main__": root = tk.Tk() MainApplication(root).pack(side="top", fill="both", expand=True) root.mainloop()
需要注意的重要事项是:
我不使用通配符导入。 我将包导入为“tk”,这要求我在所有命令前加上tk.. 这可以防止全局命名空间污染,而且当您使用 Tkinter 类、ttk 类或您自己的某些类时,它使代码完全显而易见。
tk.
主要应用程序是一个类 。这为您的所有回调和私有函数提供了一个私有命名空间,并且通常使您更容易组织您的代码。在程序风格中,您必须自上而下编写代码,在使用函数之前定义函数等。使用此方法您不需要,因为直到最后一步您才真正创建主窗口。我更喜欢继承 fromtk.Frame只是因为我通常从创建一个框架开始,但这绝不是必要的。
tk.Frame
如果您的应用程序有额外的顶级窗口,我建议将它们中的每一个都设为一个单独的类,继承自tk.Toplevel. 这为您提供了上面提到的所有相同优势——窗口是原子的,它们有自己的命名空间,并且代码组织良好。此外,一旦代码开始变大,就可以轻松地将每个模块放入自己的模块中。
tk.Toplevel
最后,您可能需要考虑为界面的每个主要部分使用类。例如,如果您正在创建一个带有工具栏、导航窗格、状态栏和主区域的应用程序,您可以创建这些类中的每一个。这使您的主要代码非常小且易于理解:
class Navbar(tk.Frame): ... class Toolbar(tk.Frame): ... class Statusbar(tk.Frame): ... class Main(tk.Frame): ... class MainApplication(tk.Frame): def __init__(self, parent, *args, **kwargs): tk.Frame.__init__(self, parent, *args, **kwargs) self.statusbar = Statusbar(self, ...) self.toolbar = Toolbar(self, ...) self.navbar = Navbar(self, ...) self.main = Main(self, ...) self.statusbar.pack(side="bottom", fill="x") self.toolbar.pack(side="top", fill="x") self.navbar.pack(side="left", fill="y") self.main.pack(side="right", fill="both", expand=True)
由于所有这些实例共享一个共同的父级,因此父级实际上成为模型-视图- 控制器架构的“控制器”部分。因此,例如,主窗口可以通过调用self.parent.statusbar.set("Hello, world"). 这允许您在组件之间定义一个简单的接口,有助于保持最小的耦合。
self.parent.statusbar.set("Hello, world")