pytho GUI編程之Tkinter

摘錄 python核心編程spython

GUI(Graphical User Interface)圖形用戶界面。編程

Tcl、Tk和Tkinterpython3.x

Tkinter是python的默認GUI庫。它基於Tk工具包,該工具包最初是爲工具命令語言(Tcl)設計的。Tk普及後,被移植到不少其餘的腳本語言中,包括Perl(Perl/Tk)、Ruby(Ruby/Tk)和Python(Tkinter)。服務器

安裝和使用Tkinter網絡

Tkinter在系統中不是默認必須安裝的,能夠經過在python解釋器中嘗試導入Tkinter模塊(在Python3中重命名爲tkinter)來檢查Tkinter是否可用。這裏我測試的環境是Python3.6,這裏沒有發生錯誤:架構

>>> import tkinter
>>>

若是失敗了的話,就須要從新編譯Python解釋器以使用tkinter了。框架

tkinter和Python編程函數

讓GUI程序啓動和運行起來須要如下5個步驟:工具

  1. 導入tkinter模塊
  2. 建立一個頂層窗口對象,用於容納整個GUI應用
  3. 在頂層窗口對象之上構建全部的GUI組件及其功能
  4. 經過底層的應用代碼將這些GUI組件鏈接起來
  5. 進入主事件循環

窗口和控件oop

在GUI編程中,頂層的根窗口對象包含組成GUI應用的全部的小窗口對象。它們多是文字標籤、按鈕、列表框等。這些獨立的GUI組件稱爲控件(widget)。因此當咱們說建立一個頂層窗口時,只是表示須要一個地方來擺放全部的控件。通常寫成:

top = tkinter.Tk() #或者當採用‘from tkinter import *’ 時,也可直接寫成 Tk()

tkinter.Tk()返回的對象一般稱爲根窗口,這也是一些應用使用root而不是top來指代它的緣由。

頂層窗口是那些在應用中獨立顯示的部分。GUI程序中能夠有多個頂層窗口,可是隻有一個是根窗口。

控件能夠獨立存在,也能夠做爲容器存在。若是一個控件包含其餘控件,就能夠將其認爲是那些控件的父控件。相應的,若是一個控件被其餘控件包含,則稱這個控件是那個控件的子控件。

事件驅動處理

一般,控件有一些相關的行爲,好比按下按鈕、將文本寫入文本框、敲擊回車等。這些行爲稱爲事件。而GUI對這類事件的響應稱爲回調。

一個GUI程序從開始到結束就是經過整套事件體系來驅動的,這種方式稱爲事件驅動處理。

好比,最簡單的鼠標移動。假設鼠標正停在GUI應用頂層窗口某處,將鼠標移動到另外一部分,鼠標移動的行爲會被複制到屏幕的光標上,因而看起來像是你的手在移動。系統必須處理的這些鼠標移動事件能夠繪製窗口上的指針移動。當釋放鼠標時,再也不有事件須要處理,此時屏幕會從新恢復閒置的狀態。

事件驅動的GUI處理本質上很是適合客戶端/服務器架構。當啓動一個GUI應用時,須要一些啓動步驟來準備核心部分的執行,就像網絡服務器啓動時必須先分配套接字並將其綁定到本地地址上同樣。GUI應用必須先建立全部的GUI組件,而後將他們繪製在屏幕上。這是佈局管理器的職責所在。當佈局管理器排列好全部空間後,GUI應用進入相似服務器的無限循環。這個循環一直運行,直到出現GUI事件,進行處理。

佈局管理器

Tk有3種佈局管理器來幫助控件進行定位。最原始的一種稱爲Placer。他的作法很是直接:你提供控件的大小和位置,而後交給佈局管理器。這就存在很大的問題,你必須對全部控件進行這些操做,開發者很大負擔。

第二種佈局管理器,Packer,也是咱們主要是用的。它會把控件填充到正確的位置(即指定的父控件中),而後對於以後的每一個控件,回去尋找剩餘的空間進行填充。這個處理很像是旅行時往行李箱中填充行李的過程。

第三種佈局管理器是Grid。你能夠基於網格座標,使用Grid來指定GUI空間的放置。Grid會在它們的網格位置上渲染GUI應用中的每一個對象。

本次學習中咱們使用Packer。一旦Packer肯定好全部控件的大小和對齊方式,它就會在屏幕上將其位置放置穩當。

當全部的控件擺放好後,可讓應用進入無限主循環中,代碼以下:Tkinter.mainloop()

通常來講,這是程序運行的最後一段代碼。當進入主循環後,GUI就從這裏開始接管程序的執行,全部其餘行爲都會經過回調來處理,包括退出應用。

頂層窗口:Tkinter.Tk()

以前提到的全部主要控件都是構建在頂層窗口對象之上的,該對象在tkinter中使用Tk類進行建立:

>>> import tkinter
>>> top = tkinter.Tk()

在這個窗口中,能夠放置獨立的控件,也能夠將多個組件拼湊在一塊兒構成GUI程序。下面開始介紹Tk控件

Tk控件

下面介紹了18種Tk控件(更多或者更詳細的資料參考Python主站上的Tkinter主題頁):

控件 描述
Button 於Label相似,但提供額外的功能,如鼠標懸停、按下、釋放以及鍵盤事件
Canvas 提供繪製形狀的選擇(線段、橢圓、多邊形、矩形),能夠包含圖像和位圖
Checkbutton 一組選框,能夠勾選其中的任意個(和HTML中的checkbox相似)
Entry 單行文本框,用於收集鍵盤輸入
Frame 包含其餘控件的純容器
Label 用於包含文本或圖像
LabelFrame 標籤和框架的組合,擁有額外的標籤屬性
Listbox 給用戶顯示一個選項列表進行選擇
Menu 按下Menubutton後彈出的選項列表,用戶能夠從中選擇
Menubutton 用於包含菜單(下拉、級聯等)
Message 消息,於Label相似,不過能夠顯示成多行
PanedWindow 一個能夠控制其餘控件在其中擺放的容器控件
Radiobutton 一組按鈕,其中只有一個能夠按下
Scale 線型‘滑塊’控件,根據已設定的起始值和終止值,給出當前設定的精確值
Scrollbar 爲Text、Canvas、Listbox、Enter等支持的控件提供滾動功能
Spinbox Entry和Button的組合,容許對值進行調整
Text 多行文本框,用於收集或顯示用戶輸入的文本
Toplevel 和Frame相似,不過他提供了一個單獨的窗口容器

下面先來看看一下簡單的使用:

Label控件

下面tkhello.py腳本中,展現了Tkinter應用如何啓動,着重強調了Label控件:

#python 3.6

import tkinter

top = tkinter.Tk()#建立頂層窗口
label = tkinter.Label(top,text='Hello world!')#建立標籤label,包含連個參數
label.pack()#使用Packer來管理和顯示控件
tkinter.mainloop()#運行GUI程序。這是必須的

運行效果:

 Button控件

下面的tkhello2.py腳本中,展現了按鈕控件:

#python 3.6

import tkinter

top = tkinter.Tk()#建立頂層窗口
quit = tkinter.Button(top,text='Hello World!',command=top.quit)#建立按鈕quit,包含三個參數,其中第三個參數給按鈕安裝了一個回調函數:當按下按鈕並釋放後,程序就會退出
quit.pack()#使用Packer來管理和顯示控件
tkinter.mainloop()#運行GUI程序。這是必須的

運行效果:

Label和Button控件

下面的tkhello3.py腳本中,結合了標籤和按鈕的功能,並使用了更多的參數:既包括控件的非默認參數,又展現了Packer的一些參數。fill參數告訴Packer讓‘退出’按鈕佔據剩餘的水平空間,expand參數則會引導它填充整個水平可視空間,將按鈕拉伸到左右窗口邊緣。同時,若是Packer沒有收到其餘指示,全部控件都是垂直排列的(自上而下依次排列):

 

#python 3.6

import tkinter

top = tkinter.Tk()
hello = tkinter.Label(top,text='Hello Tkinter!') #建立一個標籤
hello.pack()

quit = tkinter.Button(top,text='退出',command=top.quit,bg='red',fg='white')#建立一個退出按鈕,除了綁定一個回調函數外,還設置了背景色以及釋放按鈕時的顏色
quit.pack(fill = tkinter.X,expand=1)#

tkinter.mainloop()

 

運行效果:

Label、Button和Scale控件

下面的tkhello4.py腳本中,在以前的基礎上增長了Scale控件:

#python 3.6
from tkinter import * #雖然這種寫法會污染命名空間,可是這裏依然使用這種寫法是由於該腳本會大量引用此模塊

#該函數依附於Scale控件,當Scale控件的滑塊移動時,這個函數就會被激活。該函數會調整Label控件中的文本大小
def resize(ev = None):
    label.config(font = 'Helvetica -%d bold' % scale.get())
    
top = Tk()#頂層窗口
top.geometry('250x150+1000+500')#設置頂層窗口的屬性,250x150是指窗口大小,1000+500是指窗口在屏幕上的位置

#建立一個Label控件,擁有默認大小的字體
label = Label(top,text = 'hello world!',font = 'Helvetica -12 bold')
label.pack(fill = Y,expand=1)#經過Packer管理和顯示label控件
#建立Scale控件,該控件經過回調resize函數用來控制Label控件中字體大小的;from_屬性是滑塊最小值,to是滑塊最大值
scale = Scale(top,from_=10,to=40,orient=HORIZONTAL,command=resize)
scale.set(30)#設置滑塊的初始值
scale.pack(fill=Y,expand = 1)#經過Packer管理和顯示Scale控件

#建立一個退出按鈕控件,按下按鈕前的顏色是白色,釋放按鈕後的顏色是紅色
quit = Button(top,text='退出',command=top.quit,activeforeground='white',activebackground='red')
quit.pack()#經過Packer管理和顯示Button控件

mainloop()#主循環

運行效果:

 tkinter結合偏函數應用實例

何謂偏函數:當函數的參數個數比較多的時候,可使用functools.partial建立一個新的函數,這個新函數會固定住(凍住)原函數的部分參數,以後,當得到須要的剩餘參數後,能夠將它們解凍,一塊兒傳入到最終的參數中,從而使用最終肯定的全部參數去調用函數。簡單說就是:。functools.partial會把一個函數的某些參數設置默認值,並返回一個新函數,咱們能夠直接調用這個新函數。友情連接:偏函數

偏函數的一大優勢就是它不侷限於函數,而是能夠用於任何可調用對象(任何包括函數接口的對象),只須要使用圓括號便可,包括類、方法或可調用實例。

對於不少可調用對象,而且許多調用都反覆使用相同參數的狀況,使用偏函數會更合適。

GUI編程是一個很好的偏函數用例,由於你頗有可能須要GUI控件在外觀上具備某種一致性,而這種一致性來自於使用相同參數建立類似的對象時。想象有這麼一個應用,有不少按鈕擁有相同的背景色和前景色,對於這種只有細微差異的按鈕,每次都使用相同的參數建立相同的實例簡直是一種負擔和浪費。

下面的pfaGUI2.py腳本中,展現了一個交通路標的實例,該應用會嘗試建立文字版本的路標,並將其根據標誌類型進行區分,好比嚴重、警告、通知。而標誌類型決定了建立時的顏色方案:嚴重級別的是白底紅字,警告級別的是黃底黑字,通知級別的是白底黑字。這裏,‘嚴禁駛入’和‘錯誤路線’屬於嚴重級別,‘交通擁堵’‘火車交匯口’屬於警告級別,而‘限速’和‘單行線’屬於通知級別。該應用會建立這些標誌的按鈕,當用戶按下按鈕時,會彈出相應的對話框。

這裏要注意的版本問題,python2.x中的tkMessageBox模塊在python3.x中被重命名爲messagebox,並被整合進tkinter模塊中:

#python 3.6

from functools import partial#使用偏函數
from tkinter import Tk,X,Button#僅僅導入tkinter模塊中用到的屬性
from tkinter.messagebox import showinfo,showwarning,showerror #python 3.xb版本中對tkMessageBox重命名。這裏僅僅導入三個對話框
 #python2.x中使用from tkMessageBox import showinfo,showwarning,showerror

#定義了三個標誌 警告、嚴重、通知
WARN = 'warn'
CRIT = 'crit'
REGU = 'regu'
SIGNS = {
    '嚴謹駛入': CRIT,
    '火車交匯': WARN,
    '限速': REGU,
    '錯誤路線': CRIT,
    '交通擁堵': WARN,
    '單行線': REGU,
    'do not': CRIT
}

#對話框用做按鈕的回調函數,將在建立每一個按鈕時使用他們
critCB = lambda:showerror('Error','按下錯誤按鈕')
warnCB = lambda:showwarning('Warning','按下警告按鈕')
infoCB  = lambda:showinfo('Info','按下通知按鈕')
#啓動Tk,設置標題、位置
top = Tk()
top.title('路標')
top.geometry('250x250+700+500')#設置頂層窗口的屬性,250x250是指窗口大小,1000+500是指窗口在屏幕上的位置
Button(top,text='退出',command = top.quit,bg = 'red',fg = 'white').pack() #建立一個退出按鈕。設置前景色、背景色,並用Packer管理

MyButton = partial(Button,top)#建立了一個一階偏函數,模板化Button類和根窗口top。MyButton效果至關於tkinter.Button() 並將top做爲他的第一個參數
#下面是三個二階偏函數。二階偏函數是對一階偏函數的再次模板化。最終效果至關於使用top、回調函數和顏色這幾個參數去調用Button。
CritButton = partial(MyButton,command = critCB,bg = 'white',fg = 'red')
WarnButton = partial(MyButton,command = warnCB,bg = 'yellow')
ReguButton = partial(MyButton,command = infoCB,bg = 'white')

for eachSign in SIGNS:
    signType = SIGNS[eachSign]
    #構建一個可求值字符串cmd,該字符串包含按鈕名、傳給按鈕標籤的文本參數 和 pack()操做組成。若是是嚴重級別,會把字符大寫,不然按照標題格式輸出。這裏還使用了三元操做符。格式化字符串的時候要注意%s和%r的區別.
    #標題化函數title(),即全部單詞的首字母都大寫,其餘的字母都小寫
    cmd = '%sButton(text = %r%s).pack(fill = X,expand = True)' % \
    (signType.title(),eachSign,'.upper()' if signType ==CRIT else '.title()') #
    eval(cmd)#該函數用於執行一個字符串表達式,這裏是實例化按鈕
    
top.mainloop()#主循環,用於啓動GUI程序

運行效果圖:

 

自此,咱們算是入門了。下節咱們展現一箇中級的tkinter示例~咩

相關文章
相關標籤/搜索