【莫煩Python】Tkinter 做簡(jiǎn)單的窗口視窗 Python GUI

tkinter是一個(gè)GUI圖像窗口,例如說(shuō)我們打開(kāi)windows或者mac后都會(huì)有一個(gè)窗口,這個(gè)就是GUI界面。例如說(shuō)我們想要開(kāi)發(fā)一個(gè)計(jì)算器就需要運(yùn)用GUI界面,要開(kāi)發(fā)一個(gè)用戶(hù)可以體驗(yàn)的窗口,例如按鈕1按鈕2,我們要做的就是窗口的背后添加可視的效果。

首先我們要導(dǎo)入tkinter庫(kù)(import tkinter as tk):把tkinter用一個(gè)縮寫(xiě)tk代替。
第一步建立一個(gè)窗口,把窗口的名字這里設(shè)為window(window = tk.Tk())
第二步要給窗口弄個(gè)名字,也就是title(window.title('my window')).
第三部要給窗口設(shè)立大小,也就是長(zhǎng)寬。(window.geometry('200x100'))
第四部我們要設(shè)立一個(gè)label,也就是圖中窗口中的綠色的部分,有點(diǎn)類(lèi)似計(jì)算器顯示數(shù)字的屏幕的部分,起到一個(gè)顯示的作用,這里在視頻中首先要為label起一個(gè)名字,視頻中命名為l,然后括號(hào)里首先第一個(gè)參數(shù)是要在哪個(gè)窗口里設(shè)立這個(gè)label,然后可以設(shè)置文本、寬高,還有字體和背景顏色。
第五部分我們要設(shè)立一個(gè)pack,pack的作用是迷人將L的位置設(shè)在中上部分,而pack前的值是window的案件,這里是label,后續(xù)也可以是button等。
最后要給window加一個(gè)mainloop,使這個(gè)窗口不斷地刷新(while循環(huán)),基本上所有的窗口文件都會(huì)有一個(gè)mainloop。
其余代碼如下:
import tkinter as tk window = tk.Tk() window.title("my window") window.geometry('200x100') var = tk.StringVar() l=tk.Label(window,textvariable=var,bg='green',font=('Arial',12),width=15,height=2) #width與height的大小決定著label的大小,而決定width和height的大小的因素是字符arial的大小 l.pack() on_hit = False def hit_me(): global on_hit if on_hit == False: on_hit = True var.set('you hit me') else: on_hit=False var.set('') b = tk.Button(window,text='hit me',width=15,height=2,command=hit_me) b .pack() #pack的用處是默認(rèn)將L的位置設(shè)在中上部分 window.mainloop() #使這個(gè)窗口不斷地刷新——while循環(huán),基本上所有的窗口文件都會(huì)有一個(gè)mainloop #StringVar是Tk庫(kù)內(nèi)部定義的字符串變量類(lèi)型,在這里用于管理部件上面的字符; #這個(gè)可以跟蹤變量值的變化,普通的python變量不能即時(shí)地顯示在屏幕上面。 #StringVar并不是python內(nèi)建的對(duì)象, 而是屬于Tkinter下的對(duì)象。 #在使用界面編程的時(shí)候, 有些時(shí)候是需要跟蹤變量的值的變化,以保證值的變更隨時(shí)可以顯示在界面上。由于python無(wú)法做到這一點(diǎn),所以使用了tcl的相應(yīng)的對(duì)象,也就是StringVar、BooleanVar、DoubleVar、IntVar所需要起到的作用
因?yàn)槲覀円獙?shí)現(xiàn)的內(nèi)容是一個(gè)窗口內(nèi)有兩個(gè)組件,一個(gè)是顯示的組件label,另一個(gè)組件是按鈕button,當(dāng)我們點(diǎn)擊按鈕之后,顯示的是you hit me,而當(dāng)我們?cè)俅吸c(diǎn)擊button之后,you hit me消失。所以我們的label就不再是一個(gè)定量,也就不再只是一個(gè)text輸出去you hit me這么簡(jiǎn)單了,因?yàn)樗鼤?huì)變成無(wú)值,是一個(gè)變量,因此就要用到StringVar。將其套入到label當(dāng)中。
#StringVar并不是python內(nèi)建的對(duì)象, 而是屬于Tkinter下的對(duì)象。 #在使用界面編程的時(shí)候, 有些時(shí)候是需要跟蹤變量的值的變化,以保證值的變更隨時(shí)可以顯示在界面上。由于python無(wú)法做到這一點(diǎn),所以使用了tcl的相應(yīng)的對(duì)象,也就是StringVar、BooleanVar、DoubleVar、IntVar所需要起到的作用
然后我們要定義一個(gè)hit_me,這個(gè)hit_me命名為任意值均可,至于global,我認(rèn)為它是一個(gè)儲(chǔ)存被定義的hit_me值得倉(cāng)庫(kù),然后我們用if...else進(jìn)行一個(gè)循環(huán)。這里要注意hit_me和on_hit的區(qū)別,hit_me一是按鈕button的顯示的內(nèi)容text,二是定義的函數(shù)在button中被command來(lái)鏈接,而on_hit是一個(gè)值,要么為Fales要么為T(mén)rue,這里在循環(huán)前將on_hit的值設(shè)為Fales,然后再hit_me函數(shù)所嵌套的循環(huán)當(dāng)中,如果on_hit的值為Falese,那么執(zhí)行兩個(gè)操作,先是將on_hit的值由假變?yōu)檎?,同時(shí)輸出you hit me 的字樣,那么在判斷結(jié)束后真值存入global(前面說(shuō)過(guò)它理解為是一個(gè)倉(cāng)庫(kù)),當(dāng)我們?cè)俅吸c(diǎn)擊的時(shí)候是第二次判斷,此時(shí)將第一次循環(huán)后由假變真的值從global中調(diào)用出來(lái)判斷,因?yàn)榇藭r(shí)是真值從而執(zhí)行else,首先將真變?yōu)榧?,同時(shí)輸出的內(nèi)容為空。
定義完函數(shù)后簡(jiǎn)單地創(chuàng)建一個(gè)button,顯示在window窗口當(dāng)中,默認(rèn)文本為hit me,再設(shè)立寬高和內(nèi)置的鏈接函數(shù)command。這里主義我們的pack前面要新建一個(gè),命名為b,因?yàn)閎utton設(shè)立的名字也是b,執(zhí)行即可成功,這也就是第一個(gè)簡(jiǎn)單而又充滿(mǎn)難度的window窗口的結(jié)束。
上一次講到了label和button,這次我們要講的一個(gè)是用來(lái)輸入用戶(hù)名或密碼這個(gè)輸入框的作用的東西entry,然后我們還需要用到兩個(gè)button,最下面還有一個(gè)text,一個(gè)按鈕用來(lái)將上面的內(nèi)容復(fù)制到指針上,下面的那妞用來(lái)將上面的內(nèi)容復(fù)制到最后面。
我們例如說(shuō)在登陸qq時(shí)的輸入框密碼中,輸入的字符都是*,這里就用到了entry里的show(show=‘*’)
import tkinter as tk window = tk.Tk() window.title("my window") window.geometry('200x280') e = tk.Entry(window,show='*') e.pack() def insert_point(): var = e.get() t.insert('insert',var) def insert_end(): var=e.get() t.insert('end',var) b1=tk.Button(window,text='insert point',width=15,height=2,command=insert_point) b1.pack() b2 = tk.Button(window,text='insert end',command=insert_end) b2.pack() t=tk.Text(window,height=2) t.pack()
首先明確一點(diǎn)的是我們創(chuàng)立了兩個(gè)button,因此就需要定義兩個(gè)函數(shù),這兩個(gè)函數(shù)所實(shí)現(xiàn)的目的一個(gè)是用來(lái)將輸入的內(nèi)容在鼠標(biāo)所處的位置下輸出,另一個(gè)按鈕是用來(lái)在文本末尾輸出,我們將前者命名為insert_point,后者命名為insert_end,并且兩個(gè)按鈕默認(rèn)顯示的內(nèi)容(text)也是二者。其次我們要設(shè)立一個(gè)顯示我們輸入的內(nèi)容的組件entry,這個(gè)entry是要在window下顯示的(因?yàn)槟壳拔覀儎?chuàng)建的窗口命名為window),所以window也就是entry第一個(gè)參數(shù),意思是把這個(gè)entry組件放置到名稱(chēng)為window的窗口下,show前面提過(guò)是顯示的意思,視頻末尾作者還講過(guò)可以把*設(shè)為1,那樣子用戶(hù)所輸入的一切內(nèi)容顯示出來(lái)的就只會(huì)是1(但實(shí)際內(nèi)容時(shí)不變的),讓用戶(hù)誤認(rèn)為電腦中了病毒。接下來(lái)的兩個(gè)函數(shù),二者的區(qū)別只是說(shuō)把entry中的內(nèi)容追加到text當(dāng)中的位置不一樣而已,內(nèi)容是一樣的,所以都有同一行代碼(var = e.get()),就是說(shuō)設(shè)立一個(gè)常量名為var,它的內(nèi)容是使用get將e(entry)的所有內(nèi)容獲取初來(lái),之所以是e而不是entry,是因?yàn)槲覀儼裡ntry的內(nèi)容組合成了一個(gè)量為e,這個(gè)e就代表這個(gè)entry,賦值的意思,好比說(shuō)a=15,所以輸入a的話就會(huì)顯示出15一樣。t.insert里面有連個(gè)值,一個(gè)是insert/end,另一個(gè)是var,這行代碼的意思是:insert是插入,end是末尾,由于沒(méi)有指定位置所以默認(rèn)直接插入到鼠標(biāo)所指的位置,指定了末尾的話就是在最后面插入,而同時(shí)視頻中也講了我們可以不用insert直接指定行列,例如視頻中的2.2意思就是插入到第二行的第二列(這里要注意的是python中的列是從零開(kāi)始的)。

這次要學(xué)習(xí)的組件叫做:List。而今天要做的就是在上面有一個(gè)黃色的label,然后我們選中下面的眾多數(shù)字當(dāng)中的一個(gè),然后單擊名為print selection的組件就會(huì)在黃色部分所顯示。
首先我們要知道完成這個(gè)項(xiàng)目需要用到哪些東西,名為print selection的按鈕button不必多說(shuō),而上面的黃色區(qū)域和下面一大堆的數(shù)字區(qū)域則分別需要用到的是前面我們所學(xué)的lebel,和這次我們要學(xué)習(xí)用到的listbox。listbox名如其名,list是列表,box是箱子,合起來(lái)就是一個(gè)用來(lái)存儲(chǔ)數(shù)據(jù)的盒子按以列的方式顯示出來(lái)。之前我們說(shuō)過(guò)在python中是不支持跟蹤變量的值發(fā)生變化的,因此我們還是分別需要給這兩個(gè)組件都加上StringVar,這里給黃色區(qū)域命名為var1,而下面的區(qū)域設(shè)置為var2。
import tkinter as tk window = tk.Tk() window.title("my window") window.geometry('200x280') var1 = tk.StringVar() l = tk.Label(window,bg='yellow',width=4,textvariable=var1) l.pack() def print_selection(): #為了光標(biāo)選擇這一項(xiàng),就會(huì)到label標(biāo)簽當(dāng)中,因此要設(shè)立一個(gè)這樣的函數(shù)。 value = lb.get(lb.curselection()) #curse是光標(biāo),selection是選擇,,get是得到,讓value得到光標(biāo)選擇的值。 var1.set(value) #set是放置,將光標(biāo)選擇的值value放置到var1(黃色區(qū)域)內(nèi) b1=tk.Button(window,text='print selection',width=15,height=2,command=print_selection) b1.pack() var2 = tk.StringVar() var2.set((11,22,33,44)) #set在英文中是放置的意思,也就是說(shuō)在var2里放置四個(gè)名為11,22,33,44的數(shù)字,而我們要放的數(shù)字是以元組的方式放入的。 lb=tk.Listbox(window,listvariable=var2) list_items = [1,2,3,4] #創(chuàng)建一個(gè)列表,內(nèi)容是1,2,3和4。 for item in list_items: #將列表的內(nèi)容逐個(gè)插入到lb的末端。也可以用到上節(jié)課學(xué)到的index索引插入。 lb.insert('end',item) lb.insert('end',item) lb.insert(1,'first') lb.insert(2,'second') lb.delete(2) lb.pack() window.mainloop()
圖片中的第一個(gè)數(shù)據(jù)之所以是11,是因?yàn)樵镜臄?shù)據(jù)從上到家時(shí)11,22,33,44,1,2,3,4。后來(lái)手動(dòng)插入了一個(gè)名為first的數(shù)據(jù)放到了1的位置,而前面講過(guò)python的第一位是0,所以名為first的數(shù)據(jù)插入到了11的下面,而second原本是要在first的下面的,并非是現(xiàn)在的22,之所以沒(méi)有是因?yàn)樽髡哂胐elete把它給刪除了??偠灾鹤髡呦仁峭ㄟ^(guò)set將裝有11,22,33,44數(shù)據(jù)的元組放入到了var2,后來(lái)又通過(guò)循環(huán)的方式放入了1,2,3,4,最后又手動(dòng)插入了first和second連個(gè)數(shù)據(jù),然后刪除了second。

Radiobutton選擇按鈕,類(lèi)似于一個(gè)調(diào)查問(wèn)卷,問(wèn)你是男還是女,如果你選擇了男,那么顯示你該去男廁所上廁所,如果你是個(gè)女的,那就顯示你應(yīng)該去女廁所上廁所。而視頻中作者的內(nèi)容是需要三個(gè)radiobutton,名字分別為OptionABC。同時(shí)還需要設(shè)立一個(gè)label來(lái)顯示我們點(diǎn)擊按鈕后所呈現(xiàn)出的內(nèi)容。
import tkinter as tk window = tk.Tk() window.title("my window") window.geometry('200x200') var = tk.StringVar() l = tk.Label(window,bg='yellow',width=24,text='empty') l.pack() def print_selection(): l.config(text='you have selected'+var.get()) r1=tk.Radiobutton(window,text='Option A',variable=var,value='A',command=print_selection) r1.pack() r2=tk.Radiobutton(window,text='Option B',variable=var,value='B',command=print_selection) r2.pack() r3=tk.Radiobutton(window,text='Option C',variable=var,value='C',command=print_selection) r3.pack() window.mainloop()
Radiobutton的選項(xiàng)首先要指定其設(shè)置在哪個(gè)窗口中,并且顯示的字是怎樣的,然后它代表了給variable的這個(gè)var賦值成怎樣的字符,可以這樣來(lái)理解,Radiobutton這個(gè)組件自帶了一個(gè)字符存儲(chǔ)器叫variable,它是用來(lái)存儲(chǔ)數(shù)據(jù)的,而數(shù)據(jù)在這里叫做value,所以我們做的操作時(shí)將這個(gè)字符存儲(chǔ)器與前面我們所創(chuàng)建的var所掛鉤,并且字符存儲(chǔ)器里面所存儲(chǔ)的字符,也就是value我們給他取名為ABC,最后我們要定義一個(gè)函數(shù),來(lái)起到點(diǎn)擊這個(gè)按鈕的話,就會(huì)執(zhí)行這個(gè)函數(shù),這個(gè)函數(shù)是用來(lái)改變Label的,原本的text是empry,后來(lái)點(diǎn)擊按鈕之后就會(huì)改變成我們的固定字符'you have selected'加上我們給var所傳遞的內(nèi)容即可。由于顯示的內(nèi)容較長(zhǎng),因此我們需要設(shè)置至少能過(guò)讓完整字符輸出出來(lái)的而長(zhǎng)度給label。
這次要講的部件名為scale部件,它類(lèi)似于我們要拉動(dòng)的一個(gè)條,與之不同的是scale會(huì)返回一個(gè)具體的數(shù)字,在我們拉動(dòng)它的時(shí)候上面的值會(huì)改變,其實(shí)就像是測(cè)拉力的器械一樣,如果我們用力拉伸,器械上的顯示屏所顯示你的力氣就會(huì)越大。
i首先我們肯定是需要一個(gè)負(fù)責(zé)顯示數(shù)值變化的label,當(dāng)然還有我們這次要講的scale,scale內(nèi)的值與大部分組件一樣,首當(dāng)其沖的就是我們要把這個(gè)scale設(shè)置在哪個(gè)窗口,這里當(dāng)然是window了。而在scale上面有一個(gè)留白的部分,這個(gè)部分就是label,我們可以對(duì)其進(jìn)行設(shè)置讓其顯示出一些文字,就好比我們吃漢堡,中間的是精華而上下是面包,上面的面包是用來(lái)顯示名字或者標(biāo)題的,下面的面包片是用來(lái)顯示刻度的,就像本次的1.00和6.00之類(lèi)的,類(lèi)似于尺子的刻度。每一個(gè)尺子都有其特定的長(zhǎng)度,大多數(shù)為20cm,而我們的sacle可以自定義其長(zhǎng)度,這里我們?cè)O(shè)置為從5到10,并且可以控制其為橫向還是縱向的,從作者的代碼中我們可以得知橫向的參數(shù)是HORIZONTAL。接下來(lái)我們?cè)撛O(shè)置其長(zhǎng)度了,注意這里我們的長(zhǎng)度不再是字符的長(zhǎng)度了,而是像素的長(zhǎng)度,也就是和窗口的大小一樣的單位。showvalue就是我們顯示的值,在這里我們可以設(shè)置為0,也就是FALSE不顯示,同理如果是1的話就是顯示,顯示的值得位置就是在我們拖動(dòng)的指針的上面進(jìn)行顯示,之所以這次不進(jìn)行顯示是因?yàn)樵谏厦娴狞S色區(qū)域已經(jīng)顯示了,就沒(méi)有必要多此一舉了。那么接下來(lái)我們還可以設(shè)置標(biāo)簽的單位長(zhǎng)度,參數(shù)是tickterval,同時(shí)還可以設(shè)置它的保留幾位小數(shù),不保留小數(shù)(整數(shù))就是1,保留一位小數(shù)就是0.1,不保留小數(shù)就是0.01,同時(shí)為了讓scale的值能夠在黃色區(qū)域所顯示我們還需要設(shè)置一個(gè)command并設(shè)置其參數(shù)。
mport tkinter as tk window = tk.Tk() window.title("my window") window.geometry('150x200') l = tk.Label(window,bg='yellow',width=20,text='empty') l.pack() def print_selection(v): l.config(text='you have selected'+v) s=tk.Scale(window,label='try me',from_=5,to=11,orient=tk.HORIZONTAL,length=200,showvalue=1,tickinterval=3,resolution=0.01,command=print_selection) s.pack() window.mainloop()
這次要講的是Checkbutton,Checkbutton和Radiobutton雖然都是按鈕但略顯不同,如果說(shuō)Checkbutton是多選項(xiàng),那么Radiobutton是單選項(xiàng)。例如說(shuō)如下圖我們可以既喜歡python又喜歡c++(不專(zhuān)一)。

import tkinter as tk window = tk.Tk() window.title("my window") window.geometry('150x200') l = tk.Label(window,bg='yellow',width=20,text='empty') l.pack() def print_selection(): if(var1.get() ==1)&(var2.get()==0): l.config(text='I love only Python') elif (var1.get()==0) &(var2.get() ==1): l.config(text='I love only C++') elif (var1.get() ==0) & (var2.get()==0): l.config(text='I do not love either') else: l.config(text='I love both') var1=tk.IntVar() var2=tk.IntVar() c1 = tk.Checkbutton(window,text='Python',variable=var1,onvalue=1,offvalue=0,command=print_selection) c2 = tk.Checkbutton(window,text='C++',variable=var2,onvalue=1,offvalue=0,command=print_selection) c1.pack() c2.pack() window.mainloop()
&是and的意思,而config是打印的意思,作者的作品中有連個(gè)選項(xiàng)(python和c++),因此我們要設(shè)立兩個(gè)checkbutton,而為了實(shí)現(xiàn)點(diǎn)擊每一個(gè)button的時(shí)候和點(diǎn)擊兩個(gè)button時(shí)和都不點(diǎn)擊button和都點(diǎn)擊時(shí)的效果不一樣,我們同樣需要定義一個(gè)函數(shù),這個(gè)函數(shù)來(lái)實(shí)現(xiàn)我們點(diǎn)擊不同的按鈕所觸發(fā)的不同的效果,而點(diǎn)擊的按鈕的參數(shù)和radiobutton的內(nèi)容大致一樣,也是先輸入所要存在的窗口,然后輸入顯示的文本,同時(shí)分別綁定var1和var2,這個(gè)variable的值由于onvalue和offvalue的存在要么是1要么是2,至于是1還是2取決于是否點(diǎn)擊,點(diǎn)擊的話就觸發(fā)onvalue的效果讓variable的值為賦給var1,var1進(jìn)入被定義的函數(shù)中判斷,若為1則......最后用command和函數(shù)掛鉤。
今天我們要學(xué)習(xí)的是在tkinter中放置畫(huà)布,并且可以調(diào)換其位置和形狀,要想創(chuàng)建畫(huà)布,我們既要用到Canvas命令,先設(shè)置其要放置在哪個(gè)窗口,這里是window窗口,bg是北京顏色,這里是藍(lán)色,高寬分別設(shè)置成100和200,因?yàn)槲覀兊拇翱趙indow就是200*200,因此下面留白了100的部分用來(lái)房button,button只需要設(shè)置其函數(shù)即可,內(nèi)容顯示為move。而關(guān)鍵是在canvas中加入圖片,要想加入圖片,在canvas創(chuàng)建好的基礎(chǔ)上創(chuàng)建PhotoImage,然后其參數(shù)用file來(lái)掛鉤我們想要插入的圖片的名字(在mac里只支持gif格式,實(shí)測(cè)在window中也是如此,但是或許不同的版本應(yīng)該可以),然后加載的canvas是要?jiǎng)?chuàng)建圖像,首先我們要設(shè)立一個(gè)畫(huà)布中的點(diǎn),而anchor是設(shè)立錨定的點(diǎn)。具體參數(shù)如下圖:

import tkinter as tk window = tk.Tk() window.title("my window") window.geometry('200x200') canvas = tk.Canvas(window,bg='blue',height=100,width=200) image_file = tk.PhotoImage(file='hope.gif') image=canvas.create_image(10,0,anchor='nw',image=image_file)#在canvas當(dāng)中因?yàn)槭莕w,所以以左上角為原點(diǎn),而10,10就代表向下10想右10 x0,y0,x1,y1 = 50,50,80,80 line = canvas.create_line(x0,y0,x1,y1) #線段有起點(diǎn)和終點(diǎn),而我們?cè)O(shè)置線段的長(zhǎng)度要有四個(gè)數(shù)據(jù),前兩個(gè)是起點(diǎn)的x與y,后兩個(gè)是終點(diǎn)的x與y。 oval = canvas.create_oval(x0,y0,x1,y1,fill='red') #fill是設(shè)置填充的顏色 arc=canvas.create_arc(x0+30,y0+30,x1+30,y1+30,start=0,extent=180) #entent是翻轉(zhuǎn)的角度,start是扇形開(kāi)始時(shí)的邊的位置。 rect=canvas.create_rectangle(100,30,100+20,30+20) #矩形的特點(diǎn)就是對(duì)邊相等,因此我們也是只需要設(shè)立起點(diǎn)(100,30)和終點(diǎn)(120,50)即可。 def moveit(): #定義一個(gè)名為moveit的函數(shù) canvas.move(rect,0,2) #0表示x,2表示y,也就是說(shuō)橫向不變,縱向下降2的單位長(zhǎng)度,move是移動(dòng)的意思 canvas.pack() b=tk.Button(window,text='move',command=moveit).pack() window.mainloop()
這里有一個(gè)比較有意思的現(xiàn)象,作者在沒(méi)有定義moveit的時(shí)候是能將結(jié)果輸出的,但是我沒(méi)定義的時(shí)候會(huì)報(bào)錯(cuò),因此在跟著做的時(shí)候一定要先理解,看完視頻后再運(yùn)行測(cè)試。
這此要學(xué)習(xí)的內(nèi)容那個(gè)叫做Menubar,而在mac系統(tǒng)中的menubar在最上面,我們這次并不會(huì)執(zhí)著于實(shí)現(xiàn)具體的功能,而是讓其余l(xiāng)abel能夠附和在一起即可。首先我們要定義menubar,menubar不需要任何東西,只需要定義說(shuō)我們的窗口有一個(gè)menubar即可,后面我們單獨(dú)來(lái)設(shè)置。并且每一個(gè)menubar都要設(shè)置其函數(shù)內(nèi)核。同時(shí)顯示的黃色區(qū)域是用label來(lái)顯示的。

我們要實(shí)現(xiàn)的內(nèi)容是窗口左上角有名為File的選項(xiàng),點(diǎn)開(kāi)該選項(xiàng)會(huì)出現(xiàn)New、Open、Save,點(diǎn)擊New或Open或Save,三個(gè)按鈕任意點(diǎn)擊一個(gè)的話就會(huì)從do 0加一...。這三個(gè)按鈕除了顯示的text不同之外都一樣,所以command所掛鉤的函數(shù)都是相同的。我們可以看到作者的Exit上面有一個(gè)分割線,這個(gè)分割線就用:filemenu.add_separate()就好。而作者的Edit中下面的兩個(gè)按鈕呢是mac自帶的功能并非是設(shè)計(jì)的所以不用去管,只要設(shè)置Cut、Copy和Paste即可。我們可以直接copy上面已經(jīng)打好的內(nèi)容,然后改一下名字和label顯示的名字即可,而command在此演示中就不做不同的修改了,只要知道每一個(gè)功能都會(huì)執(zhí)行command所鏈接的函數(shù)的功能即可,相當(dāng)于一個(gè)框架,具體實(shí)施的內(nèi)容還是需要具體的去實(shí)現(xiàn)。最后我們?cè)谶@個(gè)File里還加了一個(gè)Import,import下面還有一個(gè)子選項(xiàng),創(chuàng)建形式和前面兩個(gè)差別不大,只不過(guò)這次因?yàn)槲覀兊膇mport是在file下,而file在filemenu下,因此import要與filemenu掛鉤。
import tkinter as tk window = tk.Tk() window.title("my window") window.geometry('200x200') l = tk.Label(window,text='',bg='yellow') l.pack() counter = 0 def do_job(): global counter l.config(text='do'+str(counter)) #改變我們label的一個(gè)參數(shù) counter+=1 menubar = tk.Menu(window) #給window窗口設(shè)立一個(gè)Menu filemenu = tk.Menu(menubar,tearoff=0) #tearoff是設(shè)置能否分開(kāi),0是不能,1是能。這里作者改成0或1沒(méi)有發(fā)現(xiàn)有什么明顯的區(qū)別 menubar.add_cascade(label='File',menu=filemenu) filemenu.add_command(label='New',command=do_job) filemenu.add_command(label='Open',command=do_job) filemenu.add_command(label='Save',command=do_job) filemenu.add_separator() filemenu.add_command(label='Exit',command=window.quit) #退出這個(gè)窗口 editmenu = tk.Menu(menubar,tearoff=0) #tearoff是設(shè)置能否分開(kāi),0是不能,1是能。這里作者改成0或1沒(méi)有發(fā)現(xiàn)有什么明顯的區(qū)別 menubar.add_cascade(label='Edit',menu=editmenu) editmenu.add_command(label='Cut',command=do_job) editmenu.add_command(label='Copy',command=do_job) editmenu.add_command(label='Paste',command=do_job) submenu=tk.Menu(filemenu) filemenu.add_cascade(label='Import',menu=submenu,underline=0) submenu.add_command(label='Submenu1',command=do_job) window.config(menu=menubar) #改變window的一個(gè)參數(shù),把它的menu改變成我們定義好的menubar window.mainloop()
后面我們要想實(shí)現(xiàn)這個(gè)內(nèi)容首先要明確一點(diǎn)的是,filemenu和file的關(guān)系,這個(gè)代碼我們創(chuàng)建了兩個(gè)menu(filemenu和editmenu),而file是filemenu下拉框下的file下的一個(gè)副選框,雖然這個(gè)復(fù)選框所在的file是在filemenu下,但是它依舊要新建立一個(gè)下拉框,也就是說(shuō)如果filemenu是老子的話,file是孩子,那么新建立的這個(gè)下拉框import雖然是孫子,但他和file不同,file是老子的一個(gè)選項(xiàng),而import是又一個(gè)新建立的下拉框,所以從輩兒上將可能不是很大,但是其內(nèi)核是與filemenu平等偏下的,之所以說(shuō)是平等偏下,是因?yàn)樗趂ilemenu下建立的,而與filemenu平等的是editmenu,他倆的老大都是menu,只能說(shuō)filemenu多了個(gè)小弟,這個(gè)小弟又收了一個(gè)小弟,因此我們要這個(gè)小弟所收的小弟建立一個(gè)新的內(nèi)核命名為submenu,這個(gè)新的內(nèi)核命名為Import,這個(gè)被收的小弟也收了一個(gè)小弟,它自立門(mén)戶(hù)當(dāng)了個(gè)老大,收了一個(gè)叫Submenu1的小弟,而file一直是小弟,沒(méi)有自立門(mén)戶(hù)。
這一次我們要學(xué)習(xí)的是Frame框架,F(xiàn)rame小部件我們是在窗口中看不到的,但是它可以總結(jié)歸納起來(lái)我們?cè)贔rame里的小部件??梢园阉氤梢粋€(gè)用來(lái)對(duì)其他組件分類(lèi)的歸納箱,把像label或者是button這樣的部件想象成垃圾,廚余垃圾分成一類(lèi),有害垃圾分成一類(lèi)。如下圖所示左邊的兩個(gè)label被一個(gè)Frame圈著,右邊的label被另一個(gè)Frame圈著,因此我們需要先定義三哥label。注意這個(gè)Frame是由主次之分的,如果說(shuō)左右兩邊的Frame是同級(jí),那么它倆都有一個(gè)共同的父集。設(shè)置其左右我們使用side參數(shù)來(lái)設(shè)置的,同時(shí)這里要注意的是設(shè)置其左右不是在window上的左右,而是在Frame上的左右

import tkinter as tk window = tk.Tk() window.title("my window") window.geometry('200x200') tk.Label(window,text='on the window').pack() frm=tk.Frame(window) frm.pack() frm_l = tk.Frame(frm,) frm_r = tk.Frame(frm) frm_l.pack(side='left') frm_r.pack(side='right') tk.Label(frm_l,text='on the frm_l1').pack() tk.Label(frm_l,text='on the frm_l2').pack() tk.Label(frm_r,text='on the frm_r1').pack() window.mainloop()
復(fù)制粘貼是好,但是我們要注意的是一定要記得修改一下??偠灾刮覀?cè)谝粋€(gè)打的frame的基礎(chǔ)上建立一個(gè)左邊的frame和右邊的frame,這樣可以讓我們更詳細(xì)地了解到我們frame的布局。
這一次我們要講述如何來(lái)放置我們所創(chuàng)造的部件,一種是我們常見(jiàn)的部件pack,前面已經(jīng)用過(guò)很多了,例如說(shuō)我們?cè)O(shè)立了一個(gè)label,那么要想讓label顯示出來(lái)就需要設(shè)立一個(gè)label.pack(),而我們似乎不知道的是pack是可以設(shè)立其位置的,例如說(shuō)我這樣的代碼。
import tkinter as tk window = tk.Tk() window.title("my window") window.geometry('200x200') tk.Label(window,text='on the window').pack(side='top') tk.Label(window,text='on the window').pack(side='bottom') tk.Label(window,text='on the window').pack(side='left') tk.Label(window,text='on the window').pack(side='right') window.mainloop()
接下來(lái)我們講一下grid,grid如果想讓它方便顯示的話我們要用到循環(huán),設(shè)置其行列,例如說(shuō)我們想設(shè)置一個(gè)四行三列的東西,我們可以這樣的代碼。
import tkinter as tk window = tk.Tk() window.title("my window") window.geometry('200x200') for i in range(4): for j in range(3): tk.Label(window,text='1').grid(row=i,column=j) window.mainloop()
這里比較難理解的就是循環(huán)的作用,實(shí)際上小編在去掉循環(huán)之后發(fā)現(xiàn)只是輸出了一個(gè)1,盡管設(shè)置了其row行尾4,column列為3還是只有一個(gè)1,所以為了方便理解,就理解為如果想要輸出類(lèi)似有規(guī)則對(duì)稱(chēng)的散點(diǎn)圖,就要在行的循環(huán)下套一個(gè)列的循環(huán)進(jìn)行使用。除了行列的代碼我們還可以設(shè)置padx和pady,二者是內(nèi)部關(guān)于x和y的擴(kuò)展,每一個(gè)文本的占地面積就會(huì)增大,也可以設(shè)置其ipadx和ipady,這個(gè)是它內(nèi)部設(shè)置的,注意所謂的擴(kuò)展是指文本與文本之間關(guān)于x與y方向的擴(kuò)展。而作者最常用的還是place,place就是從窗口的左上角為0點(diǎn),x=10就是往右移10.y=100就是往下100的距離,同時(shí)也可以設(shè)置其方向在哪里,例如anchor=‘nr’也就是西北角,這個(gè)圖我們之前學(xué)過(guò)。注意這里的100與我們熟知的xy坐標(biāo)不同的是y是反著的。
這一次講到的是tkinter的一個(gè)彈出的窗口,就例如我們點(diǎn)擊一下確定然后就會(huì)報(bào)錯(cuò),或者是點(diǎn)擊刪除之后就會(huì)彈出“你真的要?jiǎng)h除這個(gè)文件嘛”之類(lèi)的功能,
首先要想激活窗口我們就需要?jiǎng)?chuàng)立一個(gè)button,點(diǎn)擊這個(gè)按鈕之后才能有彈窗被彈出,因此這個(gè)button要連接一個(gè)函數(shù),這個(gè)函數(shù)也自然就是彈窗的函數(shù),函數(shù)名這個(gè)變量命名為hit_me,彈窗的組件叫messagebox,而作者代碼中的showinfo就是彈出的窗口中的火箭的標(biāo)志,注意不同的messagebox所彈出的圖標(biāo)是不一樣的,我們用另外一個(gè)messagebox,把火箭替換成showwarning,意思就是展示錯(cuò)誤的意思,又或者我們換成showerror,和warning相比,warning更多的是有錯(cuò)誤但影響不大,而error則是會(huì)影響主程序的圖標(biāo)展示。還有一個(gè)不是以show開(kāi)頭了,而是以ask,askquestion的返回值是一個(gè)字符串的yes或者no。點(diǎn)擊yes或者no,在python的Idle也自然會(huì)返回yes或者no。若把a(bǔ)skquestion改成askyesno的話,所返回的no或者yes對(duì)應(yīng)的就不再是它們本了,yes的返回是True,no的返回是False,而最后一個(gè)asktycancel和askokcance,他們的返回也同樣是True和Falese,和上述的內(nèi)容無(wú)異就不講了。
import tkinter.messagebox window = tkinter.Tk() window.title("my window") window.geometry('200x200') def hit_me(): tkinter.messagebox.showinfo(title='Hi',message='hahahaha') tkinter.messagebox.showwarning(title='Hi',message='nononono') tkinter.messagebox.showerror(title='Hi',message='No!never') #return 'yes','no' print(tkinter.messagebox.askys(title='Hi',message='hahahahha')) tkinter.Button(window,text='hit me',command=hit_me).pack() window.mainloop()
這里一定要注意一點(diǎn)的就是要調(diào)用messagebox,不然就會(huì)報(bào)錯(cuò)出現(xiàn)AttributeError: module ‘tkinter‘ has no attribute ‘messagebox的錯(cuò)誤,意思是Python使用對(duì)話框顯示提示信息出現(xiàn)無(wú)messagebox屬性。
這次我們要做一個(gè)小例子,也就是實(shí)踐。本次實(shí)踐要做的是一個(gè)登錄的窗口,而除了登錄的窗口按鈕還有一個(gè)注冊(cè)的窗口,這個(gè)窗口會(huì)彈出很多彈窗來(lái)跟用戶(hù)進(jìn)行一個(gè)交流。
首先在設(shè)立完基本的窗口(大小標(biāo)題都設(shè)置好了)后,我們還需要引入一個(gè)welcome的圖片,這里就不去搞了,主要把組件搞了就好,因?yàn)樽髡叩膱D片所謂的主頁(yè)未必是本網(wǎng)站。不過(guò)解釋一下作者圖片的意思,作者導(dǎo)入這個(gè)圖片運(yùn)用了PhotoImage,file與圖片名掛鉤,然后設(shè)置其圖片的位置,這個(gè)圖片的變量名我們?cè)O(shè)為image_file,所以接下來(lái)在我們學(xué)過(guò)的畫(huà)布按鈕canvas中用file函數(shù)與這個(gè)圖片掛鉤來(lái)設(shè)置這個(gè)圖片的位置。然后密碼和賬號(hào)兩個(gè)位置要用label來(lái)設(shè)置,通過(guò)從筆記上看上上節(jié)課學(xué)完的place的方式來(lái)設(shè)置組件的位置,并為兩個(gè)label來(lái)設(shè)立text告訴用戶(hù)你在哪里輸密碼哪里輸入賬號(hào),然后用戶(hù)的密碼賬號(hào)輸入框是用entry來(lái)解決,這個(gè)是變量因此我們需要用到很早就學(xué)的StringVar,賬號(hào)密碼各需要一個(gè)共兩個(gè)。同時(shí)可以用set函數(shù)設(shè)立一個(gè)默認(rèn)值給到賬號(hào),這是因?yàn)橛幸恍┯脩?hù)不記得自己的賬號(hào),因此需要這樣設(shè)置,同時(shí)密碼也可以,不過(guò)大多數(shù)平臺(tái)都會(huì)給它變成*。
然后我們還要設(shè)置一個(gè)登錄和設(shè)置面兩個(gè)按鈕,這兩個(gè)按鈕都是用place來(lái)定義位置信息,我們已經(jīng)定義好了主窗口,登錄和設(shè)置的窗口按鈕也做好了,接下來(lái)就要做一下login的功能,再做sign的功能。login是登錄的意思,登錄的時(shí)候不能說(shuō)隨便輸入一個(gè)數(shù)據(jù)就能登錄。在我們創(chuàng)建完login之后,就要?jiǎng)?chuàng)建sign up的功能,打開(kāi)sign up,就會(huì)彈出一個(gè)讓我們注冊(cè)賬號(hào)和密碼的窗口,此刻就需要個(gè)label和三個(gè)entry和一個(gè)窗口,還有一個(gè)按鈕,因?yàn)閺棾龅淖?cè)頁(yè)面和一個(gè)新的window。我們創(chuàng)建一個(gè)新的窗口命名為window_sign_up,而我們就需要運(yùn)用toplevel。Toplevel控件為其他空間提供單獨(dú)的容器,比如框架。對(duì)簡(jiǎn)單的單獨(dú)視窗應(yīng)用來(lái)說(shuō),初始化Tk時(shí)創(chuàng)建的根Toplevel可能是你所需要的唯一外框。
因?yàn)檫@個(gè)toplevel在window下,所以括號(hào)里就輸入window。然后我們?cè)僬{(diào)控好大小和標(biāo)題就可以設(shè)置組件了。完整代碼如下:
import tkinter.messagebox window=tkinter.Tk() window.title('Welcome to Mofan Python') window.geometry('450x300') var_usr_name=tkinter.StringVar() var_usr_name.set('example@python.com') entry_usr_name = tkinter.Entry(window,textvariable=var_usr_name) entry_usr_name.place(x=160,y=150) var_usr_pwd=tkinter.StringVar() entry_usr_pwd=tkinter.Entry(window,textvariable=var_usr_pwd,show="*") entry_usr_pwd.place(x=160,y=190) def usr_login(): usr_name = var_usr_name.get() usr_pwd = var_usr_pwd.get() try: with open('usrs_info.pickle','rb') as usr_file: usrs_info = pickle.load(usr_file) except FileNotFoundError: with open('usrs_info.pickle','wb') as usr_file: usrs_info={'admin':'admin'} pickle.dump(usrs_info,usr_file) if usr_name in usrs_info: if usr_pwd ==usrs_info[usr_name]: tkinter.messagebox.showinfo('Welcome','How are you?'+usr_name) else: tkinter.messagebox.showerror(message='Error,your password is wrong,try again.') else: is_sign_up = tkinter.messagebox.askyesno("Welcome You have not sign up yet,Sign up today?") if is_sign_up: usr_sign_up() def usr_sign_up(): def sign_to_Mofan_Python(): np=new_pwd.get() npf=new_pwd_confirm.get() nn=new_name.get() with open('usrs_info.pickle','rb')as usr_file: exist_usr_info = pickle.load(usr_file) if np!=npf: #如果這個(gè)新的密碼不等于庫(kù)里已有的,那么就會(huì)跳出窗口讓我們重復(fù)輸入 tkinter.messagebox.showerror('Error',"Password and confirm password must be the same!") elif nn in exist_usr_info: #如果已經(jīng)存在信息在database,就是這個(gè)用戶(hù)已經(jīng)注冊(cè)過(guò)了。 tkinter.messagebox.showerror('Error','The user has already signed up!') else: exist_usr_info[nn] = np #如果注冊(cè)合格了就把這個(gè)信息加入這里。 with open('usrs_info.pickle') as usr_file: pickle.dump(exist_usr_info,usr_file) tkinter.messagebox.showinfo('Welcome','You have successfully signed up!') window_sign_up.destroy() window_sign_up=tkinter.Toplevel(window) window_sign_up.geometry('350x200') window_sign_up.title('Sign up window') new_name=tkinter.StringVar() new_name.set('example@python.com') tkinter.Label(window_sign_up,text='User name').place(x=10,y=10) entry_new_name=tkinter.Entry(window_sign_up,textvariable=new_name) entry_new_name.place(x=150,y=10) new_pwd= tkinter.StringVar() tkinter.Label(window_sign_up, text='Password').place(x=10, y=50) entry_new_pwd = tkinter.Entry(window_sign_up, textvariable=new_pwd,show='*') entry_new_pwd.place(x=150, y=50) new_pwd_confirm=tkinter.StringVar() tkinter.Label(window_sign_up,text='Confirm password:').place(x=10,y=90) entry_usr_pwd_confirm=tkinter.Entry(window_sign_up,textvariable=new_pwd_confirm,show='*') #確認(rèn)你的密碼 entry_usr_pwd_confirm.place(x=150,y=90) btn_comfirm_sign_up = tkinter.Button(window_sign_up,text='Sign up',command=sign_to_Mofan_Python) btn_comfirm_sign_up.place(x=150,y=130) #login and sign up button btn_login=tkinter.Button(window,text='Login',command=usr_login) btn_login.place(x=170,y=230) btn_sign_up = tkinter.Button(window,text='Sign up',command=usr_sign_up) btn_sign_up.place(x=270,y=230) window.mainloop()