原文http://www.tkdocs.com/tutorial/firstexample.html

第一个实用的简易案例

A First (Real) Example
With that out of the way, let's try a slightly more useful example, which will give you an initial feel for what the code behind a Tk program looks like.
我们试着做个稍微实用的例子,通过这种方式,让你感受一下Tk的程序代码是什么样的

Design
设计
The example we'll use is a simple GUI tool that will convert a number of feet to the equivalent number of meters. If we were to sketch this out, it might look something like this:我们将用简单的GUI工具来创建这个例子。他能把英尺转换为公尺。如果我们画了草图,那他看起来应该是这个样子:

A sketch of our feet to meters conversion program.

我们的英尺转公尺程序的草图

So it looks like we have a short text entry widget that will let us type in the number of feet, and a 'Calculate' button that will get the value out of that entry, perform the calculation, and then put the resulting number of meters on the screen just below where the entry is. We've also got three static labels ("feet", "is equivalent to", and "meters") which help our user figure out how to use the interface.

看起来我们需要一个文本输入框来输入英尺,一个“Calculate”按钮来取得文本框的值并执行计算,在输入框下方输出转换后的值,我们同样需要3个标签 ("feet", "is equivalent to", 和 "meters") 帮助用户理解怎么用

In terms of layout, things seem to naturally divide into three columns and three rows:
布局方面,我们可以设计成3行3列的形式

The layout of our user interface, which follows a 3 x 3 grid.
我们界面的布局,一个3x3的网格

Code
代码
Now here is the Python code to create thie program.
下面是这程序Python代码(译注:这是python3的代码,python2中有稍许不同,下面会提到)

from tkinter import *
from tkinter import ttk
def calculate(*args):
    try:
        value = float(feet.get())
        meters.set((0.3048 * value * 10000.0 + 0.5)/10000.0)
    except ValueError:
        pass
    
root = Tk()
root.title("Feet to Meters")
mainframe = ttk.Frame(root, padding="3 3 12 12")
mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
mainframe.columnconfigure(0, weight=1)
mainframe.rowconfigure(0, weight=1)
feet = StringVar()
meters = StringVar()
feet_entry = ttk.Entry(mainframe, width=7, textvariable=feet)
feet_entry.grid(column=2, row=1, sticky=(W, E))
ttk.Label(mainframe, textvariable=meters).grid(column=2, row=2, sticky=(W, E))
ttk.Button(mainframe, text="Calculate", command=calculate).grid(column=3, row=3, sticky=W)
ttk.Label(mainframe, text="feet").grid(column=3, row=1, sticky=W)
ttk.Label(mainframe, text="is equivalent to").grid(column=1, row=2, sticky=E)
ttk.Label(mainframe, text="meters").grid(column=3, row=2, sticky=W)
for child in mainframe.winfo_children():child.grid_configure(padx=5, pady=5)
feet_entry.focus()
root.bind('<Return>', calculate)
root.mainloop()

And the resulting user interface:

Screenshot of our completed feet to meters user interface (on Mac OS X, Windows and Linux).
程序运行的截图

Step-by-Step Walkthrough
分步演练
Let's take a closer look at that code, piece by piece. For now, all we're trying to do is get a basic understanding of the types of things we need to do to create a user interface in Tk, and roughly what those things look like. We'll go into details later.
让我们看看这些代码,一点点来,现在我们要做的事情是,对我们要创建一个Tk界面有一个基本理解并知道他大概是什么样的,稍后我们来讲讲细节.

Python3代码:

from tkinter import *
from tkinter import ttk

Python2代码:

from Tkinter import *
import ttk #python2中ttk是独立的模块

These two lines tell Python that our program needs two modules. The first, "tkinter", is the standard binding to Tk, which when loaded also causes the existing Tk library on your system to be loaded. The second, "ttk", is Python's binding to the newer "themed widgets" that were added to Tk in 8.5.
这两行代码告诉Python我们的程序需要两个模块,第一个是tkinter,这个Tk所必须的,导入这个模块时你系统中的Tk相关库也会同时被加载。第二个是ttk,这是Tk 8.5版本后新增的主题控件(译注:关于python中Tk的版本。可以在导入tkinter模块后执行tkinter.Tcl().eval('info patchlevel')或者Tkinter.Tcl().eval('info patchlevel')查看版本,前者是python2,后者是pyhton3。Tk在从python2迁移到python3时把名字从Tkinter改成了tkinter)

tips:
提示:
Notice that we've imported everything from the tkinter module, so that we can call tkinter functions etc. without prefixing them, which is standard Tkinter practice. However, because we've imported just "ttk" itself, that means we'll need to prefix anything inside that module. So for example calling "Entry(...)" would invoke the function inside the tkinter module, while we'd need "ttk.Entry(...)" to invoke the function inside ttk. As you'll see, several functions are defined in both modules, and sometimes you will need both, depending on the context. Making the ttk calls explicit facilitates this, and will be the style used in this tutorial.
注意,我们导入了tkinter所有的模块,所以我们可以直接使用tkinter的所有功能,这是Tkinter的标准做法,然而,我们在后面导入了ttk,这意味着我们接下来要用到的组件前面都得加前缀,举个例子,直接调用“Entry”会调用tkinter内部的模块,然而我们需要的是ttk里的“Entry”,所以要用“ttk.Enter”,如你所见,许多函数在两者之中都有,如果同时用到这两个模块,你需要根据整体代码选择用哪个模块,让ttk的调用更加清晰,本教程中也会使用这种风格

root = Tk()
root.title("Feet to Meters")
mainframe = ttk.Frame(root, padding="3 3 12 12")
mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
mainframe.columnconfigure(0, weight=1)
mainframe.rowconfigure(0, weight=1)    

FYI:Yes, the "calculate" function appeared before this. We'll describe it down below, but need to include it near the start because we reference it in other parts of the program.
仅供参考:没错 ,“calculate"方法在这之前定义了,我们稍后在讨论他,但需要先在开始的地方定义好,因为之后我们会在其他地方调用到它

Next, the above lines set up the main window, giving it the title "Feet to Meters". Next, we create a frame widget, which will hold all the content of our user interface, and place that in our main window. The "columnconfigure"/"rowconfigure" bits just tell Tk that if the main window is resized, the frame should expand to take up the extra space.
接下来,上面的那些代码创建了主窗口,设置窗口的标题为“Feet to Meters”,然后,我们创建了一个frame控件,用户界面上的所有东西都包含在里面,并且放在主窗口中。columnconfigure"/"rowconfigure是告诉Tk如果主窗口的大小被调整,frame空间的大小也随之调整

feet = StringVar()
meters = StringVar()
feet_entry = ttk.Entry(mainframe, width=7, textvariable=feet)
feet_entry.grid(column=2, row=1, sticky=(W, E))
ttk.Label(mainframe, textvariable=meters).grid(column=2, row=2, sticky=(W, E))
ttk.Button(mainframe, text="Calculate", command=calculate).grid(column=3, row=3, sticky=W)

FYI:
Strictly speaking, we could just put the other parts of our interface directly into the main root window, without the intervening content frame. However, the main window isn't itself part of the "themed" widgets, so its background color wouldn't match the themed widgets we will put inside it. Using a "themed" frame widget to hold the content ensures that the background is correct.
仅供参考:严格来讲,我们要做的仅仅是把其他控件直接塞进主窗口中就行,不需要使用frame空间。然而,主窗口自身并不是“带主题”的控件的一部分,所以如果我们把“带主题”的控件放入主窗口,他的背景颜色不能和“带主题”的控件相匹配。用一个frame控件可以使得“带主题”的控件和主窗口的背景相匹配

The preceding lines create the three main widgets in our program: the entry where we type the number of feet in, a label where we put the resulting number of meters, and the calculate button that we press to perform the calculation.

上面的那几行代码为我们的程序创建了3个主要的控件:用来输入英尺的输入框,一个用来输出转换成米单位结果的标签,和一个执行计算的计算按钮

For each of the three widgets, we need to do two things: create the widget itself, and then place it onscreen. All three widgets, which are 'children' of our content window are created as instances of one of Tk's themed widget classes. At the same time as we create them, we give them certain options, such as how wide the entry is, the text to put inside the Button, etc. The entry and label each are assigned a mysterious "textvariable"; we'll see what that does shortly.

关于这三个控件,我们要做的就两件事:创建,显示。这三个控件都是窗口的“孩子”,“带主题”控件的类的实例。同时我们为他们设置一些选项,比如输入的宽度,按钮显示的文本等等。输入框和标签都带了一个神秘的参数“textvariable”。我们不久后还会再看到他

If the widgets are just created, they won't automatically show up on screen, because Tk doesn't know how you want them to be placed relative to other widgets. That's what the "grid" part does. Remembering the layout grid for our application, we place each widget in the appropriate column (1, 2 or 3), and row (also 1, 2 or 3). The "sticky" option says how the widget would line up within the grid cell, using compass directions. So "w" (west) means anchor the widget to the left side of the cell, "we"(west-east) means anchor it to both the left and right sides, and so on.
如果控件仅仅被创建了,他们是不会自动显示在屏幕上的,因为Tk并不知道这些控件和其他控件的位置关系。那是“grid”那个部分要做的事情。还记得我们程序的网格布局么?我们把每个控件放到对应行或者列中,”sticky“选项指明控件在网格单元中的排列,用的是指南针方向。所以“w”代表固定这个控件在左边的网格中。
“we”代表固定这个空间在左右之间。等等

ttk.Label(mainframe, text="feet").grid(column=3, row=1, sticky=W)
ttk.Label(mainframe, text="is equivalent to").grid(column=1, row=2, sticky=E)
ttk.Label(mainframe, text="meters").grid(column=3, row=2, sticky=W)

The above three lines do exactly the same thing for the three static text labels in our user interface; create each one, and place it onscreen in the appropriate cell in the grid.
上面这三行明确的为三个静态标签做了一点小工作:创建,然后放在适合的网格位置中

for child in mainframe.winfo_children(): child.grid_configure(padx=5, pady=5)
feet_entry.focus()
root.bind('<Return>', calculate)

The preceding three lines help put some nice finishing touches on our user interface.
这三行在界面上做了一些漂亮的收尾工作

The first line walks through all of the widgets that are children of our content frame, and adds a little bit of padding around each, so they aren't so scrunched together. We could have added these options to each "grid" call when we first put the widgets onscreen, but this is a nice shortcut.
第一行处理了frame中的所有控件,并且为每个空间四周添加了一些空隙,不会显得揉成一团。我们可以在之前调用grid的时候做这些事,但上面这样做也是个不错的选择

The second line tells Tk to put the focus on our entry widget. That way the cursor will start in that field, so the user doesn't have to click in it before starting to type.
第二行告诉Tk让我们的输入框获取到焦点。这方法可以让光标一开始就在输入框的位置,用户就可以不用再去点击了

The third line tells Tk that if the user presses the Return key (Enter on Windows) anywhere within the root window, that it should call our calculate routine, the same as if the user pressed the Calculate button.
第三行告诉Tk如果用户在窗口中按下了回车键,就执行计算,等同于用户按下了计算按钮

def calculate(*args):
try:
    value = float(feet.get())
    meters.set((0.3048 * value * 10000.0 + 0.5)/10000.0)
except ValueError:
    pass

Here we define our calculate procedure, which is called either when the user presses the Calculate button, or hits the Return key. It performs the feet to meters calculation, taking the number of feet from our entry widget, and placing the result in our label widget.
这里我们定义了计算过程,无论是按回车还是点计算按钮,他都会从输入框中取得把英尺,转换成米,然后输出到标签中

Say what? It doesn't look like we're doing anything with those widgets! Here's where the magic"textvariable" options we specified when creating the widgets come into play. We specified the global variable "feet" as the textvariable for the entry, which means that anytime the entry changes, Tk will automatically update the global variable feet. Similarly, if we explicitly change the value of a textvariable associated with a widget (as we're doing for "meters" which is attached to our label), the widget will automatically be updated with the current contents of the variable. Slick.
怎么样,他看起来和前面那些控件完全不一样,之前定义的那个魔术般的“textvariable”选项,在这里开始发挥作用,我们指定了全局变量“feet”成为一个textvariable来接受输入的内容,这意味着任何时候输入的值被改变,Tk都会自动的改变“feet”这个全局变量的值,同样的,如果我们明确改变了一个textvariable相关联的的控件的值(类似我们改变meters变量就改变了标签一样),控件会自动更新相应的变量。

root.mainloop()

This final line tells Tk to enter its event loop, which is needed to make everything run.
最后一行是告诉Tk进入事件循环,这是让程序能运行所必须的


黑色芝麻
78 声望1 粉丝