python GUI程式設計
GUI:Graphical User Interface圖形使用者介面
1 簡介
Tkinter是Python的預設GUI庫, 基於Tk工具包,該工具包最初是為工具命令語言(Tool Command Language,Tcl)設計的。Tk普及後,被移植到很多其他的指令碼語言中,包括Perl(Perl/Tk)、Ruby(Ruby/Tk)和Python(Tkinter)。
Python3模組為tkinter。
2 Tkinter和python程式設計
2.1 新增Tk到應用中
讓GUI 程式啟動和執行起來需要以下5 個主要步驟:
1.匯入tkinter模組。
2.建立一個頂層視窗物件,用於容納整個GUI應用。
3.在頂層視窗物件之上(或者“其中”)構建所有的GUI 元件(及其功能)。
4.通過底層的應用程式碼將這些GUI元件連線起來。
5.進入主事件迴圈
2.2 GUI程式設計介紹
1、視窗與控制元件
在GUI程式設計中,頂層的根視窗物件包含組成GUI應用的所有小視窗物件。它們可能是文字標籤、按鈕、列表框等。這些獨立的GUI元件稱為控制元件。所以當我們說建立一個頂層視窗時,只是表示需要一個地方來擺放所有的控制元件。
tkinter.Tk()返回的物件通常稱為根視窗
2、事件驅動處理
一個GUI應用從開始到結束就是通過整套事件體系來驅動的,事件可以包括按鈕按下(及釋放)、滑鼠移動、敲擊回車鍵等。
當佈局管理器排列好所有控制元件後,GUI應用進入其類似伺服器的無限迴圈。這個迴圈會一直執行,直到出現GUI事件,進行處理,然後再等待更多的事件去處理
3、佈局管理
Tk有3 種佈局管理器:
1) Placer:提供控制元件的大小和擺放位置,然後管理器就會將其擺放好
2) Packer:主要使用,把控制元件填充到正確的位置,然後對於之後的每個控制元件,會去尋找剩餘的空間進行填充
3) Grid:基於網格座標,使用Grid來指定GUI控制元件的放置
2.3 Tk控制元件
控制元件 |
描述 |
Button |
與Label類似,但提供額外的功能,如滑鼠懸浮、按下、釋放以及鍵盤活動/事件 |
Canvas |
提供繪製形狀的功能(線段、橢圓、多邊形、矩形),可以包含影象或點陣圖 |
Checkbutton |
一組選框,可以勾選其中的任意個(與HTML的checkbox輸入類似) |
Entry |
單行文字框,用於收集鍵盤輸入(與HTML的文字輸入類似) |
Frame |
包含其他控制元件的純容器 |
Label |
用於包含文字或影象 |
LabelFrame |
標籤和框架的組合,擁有額外的標籤屬性 |
Listbox |
給使用者顯示一個選項列表來進行選擇 |
Menu |
按下Menubutton後彈出的選項列表,使用者可以從中選擇 |
Menubutton |
用於包含選單(下拉、級聯等) |
Message |
訊息。與Label類似,不過可以顯示成多行 |
PanedWindow |
一個可以控制其他控制元件在其中擺放的容器控制元件 |
Radiobutton |
一組按鈕,其中只有一個可以“按下”(與HTML的radio輸入類似) |
Scale |
線性“滑塊”控制元件,根據已設定的起始值和終止值,給出當前設定的精確值 |
Scrollbar |
為Text、Canvas、Listbox、Enter等支援的控制元件提供滾動功能 |
Spinbox |
Entry 和Button 的組合,允許對值進行調整 |
Text |
多行文字框,用於收集(或顯示)使用者輸入的文字(與HTML的textarea類似) |
Toplevel |
與Frame類似,不過它提供了一個單獨的視窗容器 |
2.4 Tkinter示例
2.4.1 Label控制元件
1 import tkinter 2 3 top = tkinter.Tk() #建立了一個頂層視窗 4 5 label = tkinter.Label(top,text='Hello World!') #Label控制元件,包含Hello World字串 6 label.pack() #使用Packer來管理和顯示控制元件 7 tkinter.mainloop() #執行GUI應用,tkinter.mainloop()可以讓應用進入無限主迴圈中
執行結果:
2.4.2 Button控制元件
1 import tkinter 2 3 top = tkinter.Tk() #建立了一個頂層視窗 4 5 #Button控制元件,當按鈕被按下(並且釋放)後,整個程式就會退出 6 label = tkinter.Button(top,text='quit',command=top.quit,bg='red',fg='green') 7 label.pack() #使用Packer來管理和顯示控制元件 8 tkinter.mainloop() #執行GUI應用,tkinter.mainloop()可以讓應用進入無限主迴圈中
執行結果:
2.4.3 偏函式應用
1)偏函式
functools.partial
偏函式
的作用就是,把一個函式的某些引數給固定住(也就是設定預設值),返回一個新的函式,呼叫這個新函式會更簡單
2)偏函式應用示例
1 from functools import partial as pto #偏函式 2 from tkinter import Tk,Button,X 3 from tkinter.messagebox import showinfo,showwarning,showerror 4 5 WARN = 'warn' 6 CRIT = 'crit' 7 REGU = 'regu' 8 9 SIGNS = { 10 'do not enter':CRIT, 11 'railroad crossing':WARN, 12 '55\nspeed limit':REGU, 13 'wrong way':CRIT, 14 'merging traffic':WARN, 15 'one way':REGU 16 } 17 18 ##各種標誌型別按鈕的回撥函式## 19 critCB = lambda:showerror('Error','Error Button Pressed!') 20 warnCB = lambda:showwarning('Warning','Warning Button Pressed!') 21 infoCB = lambda:showinfo('Info','Info Button Pressed!') 22 23 top = Tk() #頂層視窗 24 top.title('Road Signs') #設定標題 25 Button(top,text='QUIT',command=top.quit,bg='red',fg='white').pack() #設定QUIT按鈕,使用Packer來管理和顯示控制元件 26 27 ##偏函式用法## 28 #模板化Button類和根視窗top;呼叫MyButton時,就會呼叫Button類(tkinter.Button()建立一個按鈕),並將top作為它的第一個引數 29 MyButton = pto(Button,top) 30 #模板化每種標誌型別,建立單獨的按鈕型別 31 CritButton = pto(MyButton,command=critCB,bg='white',fg='red') 32 WarnButton = pto(MyButton,command=warnCB,bg='goldenrod1') 33 ReguButton = pto(MyButton,command=infoCB,bg='white') 34 35 for eachSign in SIGNS: 36 signType = SIGNS[eachSign] 37 ''' 38 expand置1 使能fill屬性 39 expand置0 關閉fill屬性 40 fill=X 當GUI窗體大小發生變化時,widget在X方向跟隨GUI窗體變化 41 fill=Y 當GUI窗體大小發生變化時,widget在Y方向跟隨GUI窗體變化 42 fill=BOTH 當GUI窗體大小發生變化時,widget在X、Y兩方向跟隨GUI窗體變化 43 ''' 44 # title() 方法返回"標題化"的字串,就是說所有單詞都是以大寫開始,其餘字母均為小寫 45 cmd = '%sButton(text=%r%s).pack(fill=X,expand=True)' % (signType.title(),eachSign,'.upper()' if signType == CRIT else '.title()') 46 #eval()將字串str當成有效的表示式來求值並返回計算結果 47 eval(cmd) 48 49 top.mainloop()
執行結果:
2.4.4 Tkinter示例(目錄樹遍歷)
1 import os 2 from time import sleep 3 from tkinter import * 4 5 class DirList(object): 6 def __init__(self,initdir=None): 7 self.top = Tk() #頂層視窗 8 self.label = Label(self.top,text='Directory Lister V1.1') #Label控制元件,包含字串 9 self.label.pack() #使用Packer來管理和顯示控制元件 10 11 self.cwd = StringVar(self.top) #用於儲存當前所在的目錄名 12 13 #用於顯示當前的目錄名 14 self.dirl = Label(self.top,fg='blue',font=('Helvetica',12,'bold')) 15 self.dirl.pack() 16 17 #Scrollbar與Listbox控制元件包含在Frame控制元件中 18 self.dirfm = Frame(self.top) 19 self.dirsb = Scrollbar(self.dirfm) #檔案樹超過Listbox的大小能夠移動列表 20 #side按扭停靠在視窗的哪個位置,fill填充(x:水平方向,y:豎直方向,both:水平和豎直方向,none:不填充) 21 self.dirsb.pack(side=RIGHT,fill=Y) 22 #列出目錄的檔案列表,yscrollcommand建立一個垂直滾動條 23 self.dirs = Listbox(self.dirfm,height=15,width=50,yscrollcommand=self.dirsb.set) 24 #繫結操作,這意味著將一個回撥函式與按鍵、滑鼠操作或者其他的一些事件連線起來,這裡當雙擊任意條目時,會呼叫setDirAndGo函式 25 self.dirs.bind('<Double-1>',self.setDirAndGo) 26 self.dirs.pack(side=LEFT,fill=BOTH) 27 self.dirfm.pack() 28 29 #建立一個文字框,可以輸入遍歷的目錄名 30 #Entry是tkinter 用來接收字串等輸入的控制元件 31 self.dirn = Entry(self.top,width=50,textvariable=self.cwd) 32 #回車繫結 33 self.dirn.bind('<Return>',self.doLS) 34 self.dirn.pack() 35 36 #定義一個按鈕框架 37 self.bfm = Frame(self.top) 38 self.clr = Button(self.bfm,text='Clear',command=self.clrDir,activeforeground='white',activebackground='blue') 39 self.ls = Button(self.bfm,text='List Directory',command=self.doLS,activeforeground='white',activebackground='green') 40 self.quit = Button(self.bfm,text='Quit',command=self.top.quit,activeforeground='white',activebackground='red') 41 self.clr.pack(side=LEFT) 42 self.ls.pack(side=LEFT) 43 self.quit.pack(side=LEFT) 44 self.bfm.pack() 45 46 #初始化GUI程式,以當前工作目錄作為起始點 47 if initdir: 48 self.cwd.set(os.curdir) #os.curdir:返回當前目錄('.') 49 self.doLS() 50 51 ''' 52 清空TK字串變數cwd,當發生錯誤時可以回到之前的目錄 53 ev預設為None,值是有視窗系統傳入的,回撥函式中可能會用到,也可能用不到 54 ''' 55 def clrDir(self,ev=None): 56 self.cwd.set('') 57 58 #設定要遍歷的目錄函式 59 def setDirAndGo(self,ev=None): 60 self.last = self.cwd.get() 61 self.dirs.config(selectbackground='red') #雙擊時,設定背景色為紅色 62 check = self.dirs.get(self.dirs.curselection()) #curselection()返回當前選中項的索引,get()返回制定索引的項值 63 if not check: 64 check = os.curdir 65 self.cwd.set(check) 66 self.doLS() 67 68 def doLS(self,ev=None): 69 error='' 70 tdir = self.cwd.get() 71 if not tdir:tdir = os.curdir #os.curdir:返回當前目錄('.') 72 73 if not os.path.exists(tdir): #判斷檔案是否存在 74 error = tdir + ':no such file' 75 elif not os.path.isdir(tdir): #判斷是否是目錄 76 error = tdir + ':not a directory' 77 78 if error: 79 self.cwd.set(error) 80 self.top.update() 81 sleep(2) 82 if not (hasattr(self,'last') and self.last):#hasattr判斷一個物件裡面是否有last屬性或者last方法 83 self.last = os.curdir 84 self.cwd.set(self.last) 85 self.dirs.config(selectbackground='LightSkyBlue') 86 self.top.update() 87 return 88 89 self.cwd.set('FETCHING DIRECTORY CONTENTS...') 90 self.top.update() 91 dirlist = os.listdir(tdir) #獲取實際檔案列表 92 dirlist.sort() 93 os.chdir(tdir) #改變當前工作目錄到指定的路徑 94 95 self.dirl.config(text=os.getcwd()) #os.getcwd()返回當前程序的工作目錄 96 self.dirs.delete(0,END) #刪除所有元素 97 #insert()匯入listbox中 98 self.dirs.insert(END,os.curdir) 99 self.dirs.insert(END,os.pardir) #os.pardir上級目錄 100 for eachFile in dirlist: 101 self.dirs.insert(END,eachFile) 102 self.cwd.set(os.curdir) 103 self.dirs.config(selectbackground='LightSkyBlue') 104 105 def main(): 106 DirList(os.curdir) #os.curdir:返回當前目錄('.') 107 mainloop() 108 109 if __name__=='__main__': 110 main()
執行結果:
3 其他GUI
1) Tix(Tk介面擴充套件)
2) Pmw(Python MegaWidgets Tkinter擴充套件)
3) wxPython(wxWidgets的Python版本)
4) PyGTK(GTK+的python版本)