Python 构建 tkinter 应用程序的最佳方式?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17466561/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Best way to structure a tkinter application?
提问by Chris Aung
The following is the overall structure of my typical python tkinter program.
以下是我的典型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
and funC
will bring up another Toplevel
windows with widgets when user click on button 1, 2, 3.
funA
funB
当用户单击按钮 1、2、3 时,funC
将打开另一个Toplevel
带有小部件的窗口。
I am wondering if this is the right way to write a python tkinter program? Sure, it will work even if I write this way, but is it the best way? It sounds stupid but when I see the codes other people written, their code is not messed up with bunch of functions and mostly they have classes.
我想知道这是否是编写 python tkinter 程序的正确方法?当然,即使我这样写它也会起作用,但这是最好的方法吗?这听起来很愚蠢,但是当我看到其他人编写的代码时,他们的代码并没有被一堆函数弄得一团糟,而且大多数都有类。
Is there any specific structure that we should follow as good practice? How should I plan before start writing a python program?
有没有我们应该遵循的特定结构作为良好实践?在开始编写python程序之前我应该如何计划?
I know there is no such thing as best practice in programming and I am not asking for it either. I just want some advice and explanations to keep me on the right direction as I am learning Python by myself.
我知道编程中没有最佳实践这样的东西,我也没有要求它。我只是想要一些建议和解释,以便在我自己学习 Python 时保持正确的方向。
采纳答案by Bryan Oakley
I advocate an object oriented approach. This is the template that I start out with:
我提倡面向对象的方法。这是我开始使用的模板:
# 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()
The important things to notice are:
需要注意的重要事项是:
I don't use a wildcard import.I import the package as "tk", which requires that I prefix all commands with
tk.
. This prevents global namespace pollution, plus it makes the code completely obvious when you are using Tkinter classes, ttk classes, or some of your own.The main application is a class. This gives you a private namespace for all of your callbacks and private functions, and just generally makes it easier to organize your code. In a procedural style you have to code top-down, defining functions before using them, etc. With this method you don't since you don't actually create the main window until the very last step. I prefer inheriting from
tk.Frame
just because I typically start by creating a frame, but it is by no means necessary.
我不使用通配符导入。我将包导入为“tk”,这要求我在所有命令前加上
tk.
. 这可以防止全局命名空间污染,而且当您使用 Tkinter 类、ttk 类或您自己的一些类时,它使代码完全显而易见。主要应用程序是一个类。这为您的所有回调和私有函数提供了一个私有命名空间,并且通常可以更容易地组织您的代码。在程序风格中,您必须自上而下编写代码,在使用函数之前定义函数,等等。使用这种方法,您不需要,因为直到最后一步您才真正创建主窗口。我更喜欢继承,
tk.Frame
因为我通常从创建一个框架开始,但这绝不是必要的。
If your app has additional toplevel windows, I recommend making each of those a separate class, inheriting from tk.Toplevel
. This gives you all of the same advantages mentioned above -- the windows are atomic, they have their own namespace, and the code is well organized. Plus, it makes it easy to put each into its own module once the code starts to get large.
如果您的应用程序有额外的顶级窗口,我建议将它们中的每一个作为一个单独的类,从tk.Toplevel
. 这为您提供了上述所有相同的优点——窗口是原子的,它们有自己的命名空间,并且代码组织得很好。另外,一旦代码开始变大,它可以很容易地将每个放入自己的模块中。
Finally, you might want to consider using classes for every major portion of your interface. For example, if you're creating an app with a toolbar, a navigation pane, a statusbar, and a main area, you could make each one of those classes. This makes your main code quite small and easy to understand:
最后,您可能需要考虑为界面的每个主要部分使用类。例如,如果您正在创建一个带有工具栏、导航窗格、状态栏和主要区域的应用程序,您可以创建这些类中的每一个。这使您的主代码非常小且易于理解:
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)
Since all of those instances share a common parent, the parent effectively becomes the "controller" part of a model-view-controller architecture. So, for example, the main window could place something on the statusbar by calling self.parent.statusbar.set("Hello, world")
. This allows you to define a simple interface between the components, helping to keep coupling to a minimun.
由于所有这些实例共享一个共同的父级,父级有效地成为模型-视图-控制器架构的“控制器”部分。因此,例如,主窗口可以通过调用self.parent.statusbar.set("Hello, world")
. 这允许您在组件之间定义一个简单的接口,有助于保持最小耦合。
回答by Chris Aung
Probably the best way to learn how to structure your program is by reading other people's code, especially if it's a large program to which many people have contributed. After looking at the code of many projects, you should get an idea of what the consensus style should be.
学习如何构建程序的最好方法可能是阅读其他人的代码,尤其是当它是一个很多人都参与过的大型程序时。看了很多项目的代码,你应该知道共识风格应该是什么了。
Python, as a language, is special in that there are some strong guidelines as to how you should format your code. The first is the so-called "Zen of Python":
作为一种语言,Python 的特殊之处在于它有一些关于如何格式化代码的强有力的指导方针。首先是所谓的“Python之禅”:
- Beautiful is better than ugly.
- Explicit is better than implicit.
- Simple is better than complex.
- Complex is better than complicated.
- Flat is better than nested.
- Sparse is better than dense.
- Readability counts.
- Special cases aren't special enough to break the rules.
- Although practicality beats purity.
- Errors should never pass silently.
- Unless explicitly silenced.
- In the face of ambiguity, refuse the temptation to guess.
- There should be one-- and preferably only one --obvious way to do it.
- Although that way may not be obvious at first unless you're Dutch.
- Now is better than never.
- Although never is often better than rightnow.
- If the implementation is hard to explain, it's a bad idea.
- If the implementation is easy to explain, it may be a good idea.
- Namespaces are one honking great idea -- let's do more of those!
- 美丽总比丑陋好。
- 显式优于隐式。
- 简单胜于复杂。
- 复杂总比复杂好。
- 扁平比嵌套好。
- 稀疏比密集好。
- 可读性很重要。
- 特殊情况不足以打破规则。
- 虽然实用性胜过纯度。
- 错误永远不应该静默传递。
- 除非明确沉默。
- 面对模棱两可,拒绝猜测的诱惑。
- 应该有一种——最好只有一种——明显的方法来做到这一点。
- 尽管这种方式起初可能并不明显,除非您是荷兰人。
- 现在总比没有好。
- 虽然从未往往比右了。
- 如果实现很难解释,那是个坏主意。
- 如果实现很容易解释,这可能是一个好主意。
- 命名空间是一个很棒的想法——让我们做更多的事情!
On a more practical level, there is PEP8, the style guide for Python.
在更实用的层面上,有PEP8,Python 的风格指南。
With those in mind, I would say that your code style doesn't really fit, particularly the nested functions. Find a way to flatten those out, either by using classes or moving them into separate modules. This will make the structure of your program much easier to understand.
考虑到这些,我会说您的代码风格并不真正适合,尤其是嵌套函数。通过使用类或将它们移动到单独的模块中,找到一种方法来将它们展平。这将使您的程序结构更容易理解。
回答by Serial
This isn't a bad structure; it will work just fine. However, you do have to have functions in a function to do commands when someone clicks on a button or something
这不是一个糟糕的结构;它会工作得很好。但是,当有人单击按钮或其他东西时,您必须在函数中具有函数才能执行命令
So what you could do is write classes for these then have methods in the class that handle commands for the button clicks and such.
所以你可以做的是为这些编写类,然后在类中拥有处理按钮点击等命令的方法。
Here's an example:
下面是一个例子:
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 = Window1(root)
root.mainloop()
if __name__ == '__main__':
main()
Usually tk programs with multiple windows are multiple big classes and in the __init__
all the entries, labels etc are created and then each method is to handle button click events
通常具有多个窗口的 tk 程序是多个大类,并且在__init__
所有条目中创建标签等,然后每个方法都是处理按钮单击事件
There isn't really a right way to do it, whatever works for you and gets the job done as long as its readable and you can easily explain it because if you cant easily explain your program, there probably is a better way to do it.
没有真正正确的方法来做到这一点,任何对您有用并完成工作的方法,只要它具有可读性并且您可以轻松解释它,因为如果您无法轻松解释您的程序,那么可能有更好的方法来做到这一点.
Take a look at Thinking in Tkinter.
回答by alecxe
Putting each of your top-level windows into it's own separate class gives you code re-use and better code organization. Any buttons and relevant methods that are present in the window should be defined inside this class. Here's an example (taken from here):
将您的每个顶级窗口放入它自己的单独类中,您可以重用代码并更好地组织代码。窗口中存在的任何按钮和相关方法都应在此类中定义。这是一个示例(取自此处):
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()
Also see:
另见:
- simple hello world from tkinter docs
- Tkinter example code for multiple windows, why won't buttons load correctly?
- Tkinter: How to Show / Hide a Window
Hope that helps.
希望有帮助。
回答by gcb
I personally do not use the objected oriented approach, mostly because it a) only get in the way; b) you will neverreuse that as a module.
我个人不使用面向对象的方法,主要是因为它 a) 只会碍手碍脚;b)您永远不会将其作为模块重用。
but something that is not discussed here, is that you mustuse threading or multiprocessing. Always. otherwise your application will be awful.
但是这里没有讨论的事情是你必须使用线程或多处理。总是。否则你的申请会很糟糕。
just do a simple test: start a window, and then fetch some URL or anything else. changes are your UI will not be updated while the network request is happening. Meaning, your application window will be broken. depend on the OS you are on, but most times, it will not redraw, anything you drag over the window will be plastered on it, until the process is back to the TK mainloop.
只需做一个简单的测试:启动一个窗口,然后获取一些 URL 或其他任何内容。更改是在网络请求发生时您的 UI 不会更新。这意味着,您的应用程序窗口将被破坏。取决于您使用的操作系统,但大多数情况下,它不会重绘,您在窗口上拖动的任何内容都将粘贴在其上,直到进程返回到 TK 主循环。
回答by Trevor
OOP should be the approach and frame
should be a class variableinstead of instance variable.
OOP 应该是方法,frame
应该是类变量而不是实例变量。
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()
回答by Trevor
Organizing your application using class make it easy to you and others who work with you to debug problems and improve the app easily.
使用类组织您的应用程序使您和与您一起工作的其他人可以轻松地调试问题并轻松改进应用程序。
You can easily organize your application like this:
您可以像这样轻松地组织您的应用程序:
class hello(Tk):
def __init__(self):
super(hello, self).__init__()
self.btn = Button(text = "Click me", command=close)
self.btn.pack()
def close():
self.destroy()
app = hello()
app.mainloop()