原文http://www.tkdocs.com/tutorial/firstexample.htmlhtml
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的程序代碼是什麼樣的python
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工具來建立這個例子。他能把英尺轉換爲公尺。若是咱們畫了草圖,那他看起來應該是這個樣子:app
A sketch of our feet to meters conversion program.ide
咱們的英尺轉公尺程序的草圖函數
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") 幫助用戶理解怎麼用oop
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的網格ui
Code
代碼
Now here is the Python code to create thie program.
下面是這程序Python代碼(譯註:這是python3的代碼,python2中有稍許不一樣,下面會提到)this
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進入事件循環,這是讓程序能運行所必須的