【Tkinter】Python標準庫中的GUI框架入門之一——window和widget
本博客高度參考了這篇文章,可以認為是該文章的譯文,將分期發表。
對原作者和網站提供如此高質量的教程表示感謝!
圖形用戶界面(Graphical User Interface,簡稱GUI),是指采用圖形方式顯示計算機的操作界面。相較于命令行,這種方式上手難度低,更加容易為普通用戶所接受。
Python中有許多GUI框架,但Tkinter
是唯一一種被寫入標準庫中的。Tkinter
是跨平臺(cross-platform)的,這意味著相同的代碼可以在Windows、Linux和macOS上運行,而且GUI中的可視化元素(按鈕、文本框等)可以根據其所在的操作系統進行自動渲染。
當然,Tkinter
也有其不足之處。其中一點就是,它顯得“過時”了——許多可視化元素的樣式看起來像上個世紀的個人電腦中的一樣。如果你追求新潮、酷炫,那么Tkinter
多半沒法滿足你的要求;如果只是想實現某些功能而不怎么注重外觀,那么輕量級的Tkinter
足以讓你快速、便捷地構建自己的應用。
1. 窗口(window)
在一個GUI中,最基礎最底層的元素是窗口(window)。如果一個把一個完整的GUI比作一幅畫,那么window就是畫布,所有的操作都在這張畫布上進行。所以,在編寫GUI之前,需要創建這樣一張畫布——用編程的語言來說,就是要先實例化這樣一個window。
首先,打開Python的交互式窗口,導入tkinter
(在所有的交互代碼中,均省略了’>>>’):
import tkinter as tk
然后,實例化一個window
:
window = tk.Tk()
這時,操作系統就會彈出一個新的窗口,大概長這個樣子:
至此,畫布就準備好了,因為現在什么都沒做,所以畫布是空白的。我們可以向這張畫布上寫一些字符:
greeting = tk.Label(text='Hello Tkinter!')
greeting.pack()
最終彈窗的結果是這樣的:
第一行代碼的意思是,實例化一個Label
,在實例化的過程中,通過text
指定了該變量要顯示的內容。
第二行代碼的意思是,將該實例固定到畫布上。
Label
是Tkinter
中的一個類,單詞翻譯成中文的意思是“說明性短語”,在GUI領域,這個類被叫做“控件”(widget),通過向窗口中添加不同的控件,并對它們進行組合,就形成了各式各樣的GUI了。
Windows操作系統之所以這樣命名,就是因為它本質上就是許多window的組合,當然這些組合是非常復雜的。這些window為用戶屏蔽了看上去很枯燥的命令操作,從而提升了用戶體驗,但代價也是很巨大的,就是速度變慢。這種變慢對于普通用戶來說可能并沒有什么感覺,但是對于服務器而言,卻很可能是致命的,這也是為什么絕大部分服務器都采用沒有GUI的Linux操作系統的原因之一。
2. 控件(widget)
如果說窗口是畫布,那么控件就是不同的顏料了。它們也是組成一個GUI所必不可少的東西,是用戶與程序進行交互的基礎。在Tkinter
中,每一種控件都由一個類來定義,一些常見的控件及其說明如下:
控件 | 說明 |
---|---|
Label | 用于在屏幕上打印文本 |
Button | 按鈕,可以包含文字,并在單擊時進行相應的操作 |
Entry | 只允許單行文本輸入的控件 |
Text | 允許多行文本輸入的控件 |
Frame | 一個矩形區域,用于對控件分組或為其提供填充 |
當然,還有許多其他的控件,但上面這些確實是最基礎的,熟練使用這些控件,就可以開發一些有趣的東西,并對Tkinter
的運用有相當程度的理解。
2.1 使用Label
控件
Label
控件可以用來展示文本或者圖片。這些文本(圖片)是不能夠被用戶編輯的,上面你已經看到了一個展示文本的例子,而實際上我們還可以對展示的文本進行更多的操作:
greeting = tk.Label(
text='Hello Tkinter!',
foreground="white",
background="black"
)
greeting.pack()
很直觀,我們改變了前景色和背景色,彈窗如下:
關于顏色,可以查看顏色手冊。當然也可以使用十六進制的RGB顏色值,這更加靈活。
Tkinter
還提供了縮寫,如果你覺得background
這個單詞太長了,可以用簡寫bg
代替它,同理,可以用fg
代替foreground
。
通過指定寬度和高度,來控制控件的大小:
greeting = tk.Label(
text='Hello Tkinter!',
fg="white",
bg="black",
width=10,
height=10
)
greeting.pack()
窗口如下:
這里就存在一個問題了:寬度和高度都指定的是“10”,怎么渲染出來的不是一個正方形呢?這是因為在Tkinter
中,寬度和高度都是以文本單元(text unit)來度量的。具體來說,1單位的寬度由系統中的字符“0”或者數字0的寬度來決定,1單位的高度由系統中的字符“0”或者數字0的高度來決定。
采用這種設置而不是用英寸、厘米、像素等度量,也是為了保證程序在跨平臺運行時顯示一致。以字符來度量意味著控件大小與用戶機器上的默認字體是相關的,這樣就保證了文本能夠正確地嵌入到Label和Button中。
2.2 使用Button
控件
顧名思義,Button
控件就是用來展示一個按鈕的,點擊該按鈕,可以實現一個操作。
事實上,我們可以將Button
理解為一個可以點擊的Label
。用于創建Label
的關鍵字參數也適用于Button
控件:
button = tk.Button(
text="Click me!",
width=25,
height=5,
bg="blue",
fg="yellow",
)
彈窗是這樣的:
2.3 使用Entry
控件
當你需要收集用戶輸入的一些信息,比如用戶名、密碼等,這時候就可以使用Entry
控件了。它顯示為一個小的文本框,用戶可以在其中輸入一些文本。創建和設計Entry
控件的工作原理與上面提到的Label
和Button
非常類似:
entry = tk.Entry(fg="yellow", bg="blue", width=50)
彈窗如下:
上面已經說過,Entry
是一個單行輸入的文本框,那么一個重要的功能就是如何使用它從用戶那里獲取信息。對于一個Entry
實例,最常用的方法有三個:
.get()
:獲取Entry
實例中的文本.delete()
:刪除Entry
實例中的文本.insert()
:向Entry
實例中插入文本
下面通過具體的例子來演示這些方法的作用。
首先,創建一個GUI,其窗口顯示的內容如下:
生成這個窗口的腳本為:
import tkinter as tk
window = tk.Tk()
label = tk.Label(text='name')
entry = tk.Entry()
label.pack()
entry.pack()
需要注意的一點是,兩個控件都是居中對齊的,這也是.pack()
方法的特性之一,后文會對這個特性進行說明。
單擊一下輸入框,就可以在里面輸入內容了,假設我們輸入“Real Python”。為了驗證各個方法的作用,我們在交互式窗口接著輸入:
entry.get()
則會打印出“Real Python”的字符。
.delete()
方法用于刪除字符,其使用與對待Python中的字符串的使用方式很相似,需要傳入一個參數告訴Python刪除的字符的位置:
entry.delete(0)
即刪除了第一個字符,這時彈窗為:
如果想一次性刪除好幾個字符,還需要傳入第二個整數,用于告訴Python刪除字符的終止位置:
entry.delete(0, 4)
這時,彈窗為:
第二個數字為終止字符的位置,該位置的字符不會被刪除,上面的代碼實際上只刪除了位置為0、1、2、3的字符。
如果想一次性刪除全部,可以用如下的方法實現:
entry.delete(0, tk.END)
這時,彈窗里面的Entry
控件又為空了:
與之相反,你可以通過.insert()
方法來向控件中添加字符:
entry.insert(0, "Python")
第一個整數告訴Python從哪里開始插入字符。如果Entry
控件中沒有任何字符,那么新字符總是插入到控件的開始位置上,與你傳入的第一個參數無關。
這時的窗口又變成了這樣:
再繼續往里面插值:
entry.insert(0, "Real ")
會發現,窗口變成了第一次輸入后的樣子:
2.4 使用Text
控件
可以將Text
控件理解為一個可以輸入很多行文本的Entry
。事實上,它的作用就是如此。
與Entry
控件類似,Text
控件也有三種主要的方法:
.get()
:獲取Text
實例中的文本.delete()
:刪除Text
實例中的文本.insert()
:向Text
實例中插入文本
需要注意的是,盡管方法名稱完全一致,但由于多行文本的原因,其使用方法略有不同。
首先,我們重新創建一個帶Text
控件的GUI:
window = tk.Tk()
text_box = tk.Text()
text_box.pack()
GUI應該具有如下樣式:
單擊該Text
中的任意位置,然后就可以輸入字符了,這里我輸入了“Hello World”,占用了兩行。
與Entry
控件相類似,可以采用.get()
方法來提取Text
控件中的內容。但需要注意的是,Text
控件的.get()
方法至少需要一個參數。如果只傳入一個參數,那么你將得到該位置上的字符;如果想要得到數個字符,則需要傳入開始位置參數和終止位置參數。由于Text
控件中的內容可能包含多行,因此,每個參數都必須包含兩部分內容:字符的行號與字符在該行中的位置。
所以,位置參數的格式是<line>.<char>
。為了直觀的理解,嘗試一下下面的代碼:
text_box.get("1.0")
# 'H'
text_box.get("1.0", "1.5")
# 'Hello'
text_box.get("1.0", tk.END)
# 'Hello\nWorld\n'
注意到,換行符也是一個字符。
在理解了.get()
方法之后,相應的.delete()
方法和.insert()
方法也是通過類似的方式進行調用的。具體不再贅述,只需要記住,\n
也是一個字符。
2.5 使用Frame
控件
一個好的GUI不但有很多控件,它們之間還得通過合適的方式組合起來才行,Frame
控件就可以滿足這個要求。
可以把Frame
控件理解為其他控件的容器,在實例化其他控件時,通過master
參數來指定該控件屬于哪個Frame
。具體的,看以下代碼:
import tkinter as tk
window = tk.Tk()
frame_a = tk.Frame()
frame_b = tk.Frame()
label_a = tk.Label(master=frame_a, text="I'm in Frame A")
label_a.pack()
label_b = tk.Label(master=frame_b, text="I'm in Frame B")
label_b.pack()
frame_a.pack()
frame_b.pack()
彈窗如下:
代碼的理解也是比較直觀的:
- 5、6行實例化了兩個
Frame
控件; - 8、9行實例化了一個
Label
控件,并通過master
參數,指定了該控件包含于frame_a
中; - 11、12行操作類似;
- 14、15行將兩個
Frame
控件pack到window上; - 17行啟動了window的主循環,以保證窗口處于打開狀態。
接下來,如果我改變14和15行的順序,那么彈窗是什么樣的呢?
...
frame_b.pack()
frame_a.pack()
...
彈窗如下:
通過前后兩次實驗的對比,可以這樣理解Frame
控件的工作原理:其他控件在實例化時,通過master
參數指定了其所屬的Frame
,然后將其pack到該Frame
上。最后,將Frame
實例pack到主window上,就顯示出來各個控件了。
智能推薦
電腦空間不夠了?教你一個小秒招快速清理 Docker 占用的磁盤空間!
Docker 很占用空間,每當我們運行容器、拉取鏡像、部署應用、構建自己的鏡像時,我們的磁盤空間會被大量占用。 如果你也被這個問題所困擾,咱們就一起看一下 Docker 是如何使用磁盤空間的,以及如何回收。 docker 占用的空間可以通過下面的命令查看: TYPE 列出了docker 使用磁盤的 4 種類型: Images:所有鏡像占用的空間,包括拉取下來的鏡像,和本地構建的。 Con...
requests實現全自動PPT模板
http://www.1ppt.com/moban/ 可以免費的下載PPT模板,當然如果要人工一個個下,還是挺麻煩的,我們可以利用requests輕松下載 訪問這個主頁,我們可以看到下面的樣式 點每一個PPT模板的圖片,我們可以進入到詳細的信息頁面,翻到下面,我們可以看到對應的下載地址 點擊這個下載的按鈕,我們便可以下載對應的PPT壓縮包 那我們就開始做吧 首先,查看網頁的源代碼,我們可以看到每一...
Linux C系統編程-線程互斥鎖(四)
互斥鎖 互斥鎖也是屬于線程之間處理同步互斥方式,有上鎖/解鎖兩種狀態。 互斥鎖函數接口 1)初始化互斥鎖 pthread_mutex_init() man 3 pthread_mutex_init (找不到的情況下首先 sudo apt-get install glibc-doc sudo apt-get install manpages-posix-dev) 動態初始化 int pthread_...
統計學習方法 - 樸素貝葉斯
引入問題:一機器在良好狀態生產合格產品幾率是 90%,在故障狀態生產合格產品幾率是 30%,機器良好的概率是 75%。若一日第一件產品是合格品,那么此日機器良好的概率是多少。 貝葉斯模型 生成模型與判別模型 判別模型,即要判斷這個東西到底是哪一類,也就是要求y,那就用給定的x去預測。 生成模型,是要生成一個模型,那就是誰根據什么生成了模型,誰就是類別y,根據的內容就是x 以上述例子,判斷一個生產出...
猜你喜歡
styled-components —— React 中的 CSS 最佳實踐
https://zhuanlan.zhihu.com/p/29344146 Styled-components 是目前 React 樣式方案中最受關注的一種,它既具備了 css-in-js 的模塊化與參數化優點,又完全使用CSS的書寫習慣,不會引起額外的學習成本。本文是 styled-components 作者之一 Max Stoiber 所寫,首先總結了前端組件化樣式中的最佳實踐原則,然后在此基...
19.vue中封裝echarts組件
19.vue中封裝echarts組件 1.效果圖 2.echarts組件 3.使用組件 按照組件格式整理好數據格式 傳入組件 home.vue 4.接口返回數據格式...
【一只蒟蒻的刷題歷程】【藍橋杯】歷屆試題 九宮重排 (八數碼問題:BFS+集合set)
資源限制 時間限制:1.0s 內存限制:256.0MB 問題描述 如下面第一個圖的九宮格中,放著 1~8 的數字卡片,還有一個格子空著。與空格子相鄰的格子中的卡片可以移動到空格中。經過若干次移動,可以形成第二個圖所示的局面。 我們把第一個圖的局面記為:12345678. 把第二個圖的局面記為:123.46758 顯然是按從上到下,從左到右的順序記錄數字,空格記為句點。 本題目的任務是已知九宮的初態...