构buildtkinter应用程序的最佳方式

以下是我典型的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 funBfunC会在用户点击button1,2,3之后,带出一些带有小部件的Toplevel窗口。

我想知道这是否是正确的方式来编写一个python tkinter程序? 当然,即使我这样写,它也会工作,但这是最好的方法吗? 这听起来很愚蠢,但是当我看到其他人编写的代码时,他们的代码并没有被大量的函数搞砸,而且大部分都是类。

我们应该遵循什么样的具体结构作为好的做法? 在开始编写python程序之前,我应该如何计划?

我知道在编程中没有最好的做法,我也没有要求。 我只是想要一些build议和解释,让我自己正在学习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.前缀所有命令tk. 。 这可以防止全局命名空间的污染,而且当你使用Tkinter类,ttk类或者你自己的一些代码的时候,它会使代码变得非常明显。

  • 主要的应用是一个类 。 这为您的所有callback函数和私有函数提供了一个私有的名称空间,通常可以更容易地组织代码。 在过程风格中,你必须自上而下编码,在使用它们之前定义函数等等。使用这种方法你不会因为直到最后一步才真正创build主窗口。 我更喜欢从tk.Frameinheritance,因为我通常是从创build一个框架开始的,但这并不是必须的。

如果你的应用程序有额外的顶层窗口,我build议使每个从tk.Toplevelinheritance的单独的类。 这给你上面提到的所有相同的优点 – 窗口是primefaces的,他们有自己的名字空间,代码组织的很好。 另外,一旦代码开始变大,就可以很容易地将每个模块放入自己的模块中。

最后,您可能需要考虑为接口的每个主要部分使用类。 例如,如果您使用工具栏,导航窗格,状态栏和主区域创build应用程序,则可以制作这些类中的每一个。 这使得你的主代码非常小,易于理解:

 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")来在状态栏上放置一些东西。 这使您可以在组件之间定义一个简单的界面,帮助保持耦合到最低限度。

将每个顶层窗口放到它自己的独立类中,可以让您重新使用代码和更好的代码组织。 窗口中的任何button和相关的方法都应该在这个类中定义。 下面是一个例子(从这里拿):

 import tkinter as tk class Demo1: def __init__(self, master): self.master = master self.frame = tk.Frame(self.master) self.button1 = tk.Button(self.frame, text = 'New Window', width = 25, command = self.new_window) self.button1.pack() self.frame.pack() def new_window(self): self.newWindow = tk.Toplevel(self.master) self.app = Demo2(self.newWindow) class Demo2: def __init__(self, master): self.master = master self.frame = tk.Frame(self.master) self.quitButton = tk.Button(self.frame, text = 'Quit', width = 25, command = self.close_windows) self.quitButton.pack() self.frame.pack() def close_windows(self): self.master.destroy() def main(): root = tk.Tk() app = Demo1(root) root.mainloop() if __name__ == '__main__': main() 

另请参阅:

  • 来自tkinter文档的简单的你好世界
  • Tkinter示例代码为多个窗口,为什么不会正确加载button?
  • Tkinter:如何显示/隐藏窗口

希望有所帮助。

这不是一个糟糕的结构; 它会工作得很好。 但是,当某个人点击一个button或者某个东西时,你必须有一个函数中的函数来执行命令

所以你可以做的是编写这些类的类,然后在类中处理button点击命令等方法。

这是一个例子:

 import tkinter as tk class Window1: def __init__(self, master): pass # Create labels, entries,buttons def button_click(self): pass # If button is clicked, run this method and open window 2 class Window2: def __init__(self, master): #create buttons,entries,etc def button_method(self): #run this when button click to close window self.master.destroy() def main(): #run mianloop root = tk.Tk() app = Demo1(root) root.mainloop() if __name__ == '__main__': main() 

通常具有多个窗口的tk程序是多个大类,在__init__中创build所有条目,标签等,然后每个方法处理button单击事件

没有一个真正的方法可以做到,不pipe是否适合你,只要可读性好,你可以很容易地解释它,因为如果你不能很容易地解释你的程序,那么可能有更好的方法来做到这一点。

看看Tkinter的Thinking 。

学习如何构build程序的最好方法可能是阅读其他人的代码,特别是如果这是一个很多人贡献的大型程序。 看了很多项目的代码后,你应该了解一致的风格应该是什么。

作为一种语言,Python的特殊之处在于,对于如何格式化代码有一些强有力的指导。 首先是所谓的“Python的禅”:

  • 美丽胜过丑陋。
  • 显式比隐式更好。
  • 简单胜于复杂。
  • 复杂比复杂好。
  • 平面比嵌套更好。
  • 稀疏比密集好。
  • 可读性计数。
  • 特例不足以打破规则。
  • 虽然实用性胜过纯净。
  • 错误不应该默默通过。
  • 除非明确沉默。
  • 面对歧义,拒绝猜测的诱惑。
  • 应该有一个 – 最好只有一个 – 明显的方法来做到这一点。
  • 尽pipe这种方式一开始可能并不明显,除非你是荷兰人。
  • 现在比从未好。
  • 虽然从来没有比现在更好。
  • 如果实施很难解释,这是一个坏主意。
  • 如果实施很容易解释,这可能是一个好主意。
  • 命名空间是一个好主意 – 让我们做更多的!

在更实际的层面上,有Python的风格指南PEP8 。

考虑到这些,我会说你的代码风格并不适合,尤其是嵌套函数。 find一种方法来平整这些,无论是通过使用类或将其移动到单独的模块。 这将使您的程序结构更容易理解。

OOP应该是方法, frame应该是一个类variables而不是实例variables

 from Tkinter import * class App: def __init__(self, master): frame = Frame(master) frame.pack() self.button = Button(frame, text="QUIT", fg="red", command=frame.quit) self.button.pack(side=LEFT) self.slogan = Button(frame, text="Hello", command=self.write_slogan) self.slogan.pack(side=LEFT) def write_slogan(self): print "Tkinter is easy to use!" root = Tk() app = App(root) root.mainloop() 

在这里输入图像描述

参考: http : //www.python-course.eu/tkinter_buttons.php

我个人不会使用反对导向的方法,主要是因为它a)只能阻碍; b)你永远不会重复使用它作为一个模块。

但是这里没有讨论的是你必须使用线程或多处理。 总是。 否则你的应用程序将是可怕的。

只是做一个简单的testing:启动一个窗口,然后获取一些URL或其他东西。 networking请求发生时,您的UI将不会更新。 意思是,你的应用程序窗口将被打破。 取决于你正在使用的操作系统,但是大多数情况下,它不会重新绘制,任何你拖到窗口上的东西都会被粘贴在它上面,直到这个过程回到TK主循环。