[Toc]
# 第10章 圖形化界面
今天墨博士和小墨一起做了兩個程序:多色板和二維碼生成器。第一次做出有圖形化界面的小墨非常興奮,一起來看看吧。
小墨:墨博士,我想編一些帶界面的程序,你能教教我嗎?
墨博士:你想做什么呢?
小墨:做什么都行,只要帶界面就行。
墨博士:也好,雖然現在早已不是桌面為王的時代了,但是學點開發桌面應用程序的技能,做一些日常的小工具也不錯。
> 墨博士提醒:簡而言之,需要在本地計算機上安裝應用程序的一般可以認為是桌面應用程序,比如word、記事本、圖片查看器等。
小墨:是啊,學了這么多的內容,還不知道怎么做界面呢。
墨博士:前面的都是基礎,現在基礎學的差不多了,可以教給你一些界面相關的知識了。
小墨:太好了,我們快點開始吧。
墨博士:Python中有很多受歡迎的GUI庫,比如wxPython和PyQt。GUI是圖形用戶界面(Graphical User Interface)的簡稱,就是你說的界面。對于新手來說,除wxPython和PyQt外,使用Python自帶的tkinter也是個不錯的選擇。今天我們就來使用tkinter做幾個小應用。先來看第一個,效果如圖10.1所示。

圖10.1 第一個小應用運行結果
小墨:哇,看起來有點像瓷磚,不過顏色有點多。
墨博士:我們就叫它多色板吧。下面我們使用tkinter來制作多色板。
## 10.1 多色板
想使用tkinter,需要先將它導入進來:
```
from tkinter import *
```
因為我們可能會用到tkinter中的很多內容,所以這里使用`from tkinter import *`將tkinter中的所有內容全部引入進來。
然后創建一個窗口:
```
root = Tk()
```
這里的Tk()是創建了一個窗口,然后賦值給了變量root,這樣root就表示這個窗口了。
創建窗口后運行程序是看不到任何效果的,想看到窗口的效果,還需要加上這句:
```
root.mainloop()
```
這句話字面意思是調用主循環方法,可以理解為在實時刷新我們編寫的界面然后呈現出來。此時運行效果如圖10.2所示。

圖10.2 第一個小窗口
小墨:終于看到窗口了,這是我的第一個小窗口!
### 10.1.1 修改窗口標題和大小
墨博士:你還可以修改下窗口的標題,這個使用root的title方法:
```
root.title('我的小窗口')
```
運行效果如圖10.3所示。

圖10.3 修改標題后的窗口
小墨:這個我需要把它拖大一點才能看到我起的標題。能不能用程序把它調大一點呢?這樣運行起來就是個大窗口了。
墨博士:想設置窗口的大小,需要使用root的geometry方法:
```
root.geometry('600x400')
```
這個方法的參數`600x400`就表示創建的窗口寬度是600,高度是400,單位是像素。運行結果如圖10.4所示。

圖10.4 修改大小后的窗口
你還可以傳入`600x400+300+200`作為參數,后面的300和200指的是窗口最左上角的點在屏幕上的坐標,也即窗口在屏幕上的位置。其中300指x軸坐標的大小,200指y軸坐標的大小。對于tkinter來說,屏幕左上角是原點,從原點出發,橫向向右是x軸,縱向向下是y軸。如圖10.5所示。

圖10.5 電腦屏幕的坐標系,左上角綠點就是原點。
小墨:這樣就能定義窗口出現的任意大小和在屏幕上的任意位置了。
墨博士:接下來我們給窗口上個色,先做個單色板出來。
### 10.1.2 單色板
想給窗口上色,就要了解做桌面應用的思路。一般來說,做GUI程序就像畫畫,這里的root窗口就像畫板,一般我們不在畫板上直接畫畫,而是在畫板上鋪上一張畫紙,然后在畫紙上畫。
這里要做的單色板也用這種思路,現在定義一張畫紙出來,在tkinter中,畫紙的角色由Frame擔任。
```
# 定義基礎畫紙
frame_basic = Frame(width=600, height=400, bg='red')
```
這樣就定義好了一張畫紙。width=600和height=400用于指定畫紙的寬度和高度分別是是600和400,和畫板的大小是一樣的,這樣能正好貼在畫板上。bg='red'用于指定這張畫紙的背景顏色,bg是background的簡寫,red表示紅色,當然你也可以使用其他顏色,如blue、yellow等。
> 墨博士提醒:定義Frame時傳入的參數和前面的有所不同,是將key=value的形式一塊做了參數,如width=600。這稱為關鍵字參數。
小墨:我喜歡藍色,我要指定藍色,使用bg='blue',運行,嗯?什么都沒有?
墨博士:上面一句我們只是定義好了畫紙,指定了大小和顏色,此時的畫紙和畫板還沒有直接的關系,也就是畫紙還沒有貼上去。
小墨:那怎樣才能貼上去呢?快說吧,我都等不及了。
墨博士:這就要說說布局的概念了。對于畫板來說,畫紙貼在哪是有講究的,不能亂貼。這種如何貼畫紙的規矩,稱為布局。比如tkinter中有個grid布局,它會將畫板分成幾行幾列的網格狀,你可以選擇將畫紙貼住第幾行第幾列的格子里。就像下圖10.6所示。

圖10.6 tkinter中的grid布局,將畫板分成了n行n列
這個表格就好像畫板,我們可以將定義好的畫紙貼進去了:
```
frame_basic.grid(row=0, column=0)
```
這里的row就是行,column就是列,需要注意的是行號和列號都是從0開始的。
小墨:這樣就把畫紙貼在了第1行第1列的格子上,那此時這個畫板一共分成了多少行多少列,一共有多少個格子呢?
墨博士:一般一個界面會有很多控件構成,如輸入框、按鈕等,這就好比這里的畫板上,可能會貼上多張畫紙。在使用grid布局去貼這些畫紙的時候,不需要去事先指定共分了多少行多少列,而是根據要寫的界面的特點,將這些畫紙分別貼在不同的單元格就行了,這樣就指定好了畫紙與畫紙的相對位置關系,比如想做一個輸入框后面有個按鈕,就將輸入框放在第1行第1列,而按鈕放在第1行第2列就可以了。另外grid并不是把畫板平均分成了多少個小格子,每個小格子的大小要看實際貼進來的畫紙的大小,也即放入的控件的大小。就像這里的frame_basic,它和畫板一樣大,這樣它自己就占滿整個畫板了。
現在我把背景顏色改為orange,完整代碼如下:
```
from tkinter import *
root = Tk()
root.title('我的小窗口')
root.geometry('600x400+300+200')
# 定義畫紙,背景顏色為orange橘黃色
frame_basic = Frame(width=600, height=400, bg='orange')
# 將frame_basic放在畫板的第一行第一列,也即第一個單元格
frame_basic.grid(row=0, column=0)
root.mainloop()
```
運行結果如圖10.7所示。

圖10.7 單色板
這個就是所謂的單色板了。
### 10.1.3 四色板
接下來來做一塊四色板:屏幕分成四等份,每份一種顏色。
小墨:這個我來做。首先定義4個Frame,因為root窗口大小是600x400,所以每個Frame的大小應該是300x200,也即寬高各減半,這樣4個Frame就占滿全窗口了。然后將這4個Frame分別放在root的第1行第1列、第1行第2列、第2行第1列和第2行第2列上就可以了。代碼如下:
```
from tkinter import *
root = Tk()
root.title('我的小窗口')
root.geometry('600x400+300+200')
# 定義4個Frame,指定4種不同的背景顏色
# 600 / 2 表示600除以2,作為定義的Frame的寬度
frame1 = Frame(width=600 / 2, height=400 / 2, bg='orange')
frame2 = Frame(width=600 / 2, height=400 / 2, bg='green')
frame3 = Frame(width=600 / 2, height=400 / 2, bg='pink')
frame4 = Frame(width=600 / 2, height=400 / 2, bg='white')
# 將4個Frame依次放入指定位置
frame1.grid(row=0, column=0)
frame2.grid(row=0, column=1)
frame3.grid(row=1, column=0)
frame4.grid(row=1, column=1)
root.mainloop()
```
運行效果如圖10.8所示。

圖 10.8 四色板
墨博士:做的不錯!加大點難度,每次運行,這4個色塊的顏色都是隨機的,這個怎么做呢?
### 10.1.4 隨機顏色的四色板
小墨:可以定義一個list,里面存很多顏色,然后使用random模塊每次去隨機一個顏色的坐標,這樣就得到了隨機的顏色。
墨博士:是個好主意,但是這樣生成的顏色數量有限,我們換一種背景顏色的表達方式,能夠將顏色數量大大增加:
```
frame1 = Frame(width=600 / 2, height=400 / 2, bg='#F08080')
```
這里的背景我們設置為`#F08080`,它也表示一種顏色,為什么顏色能這樣表示呢?這就要說說RGB色彩模式了。
RGB色彩模式是一種顏色標準,目前的顯示器大都采用了這種顏色標準。這里的RGB是紅色Red,綠色Green和藍色Blue的首字母組合。電腦屏幕上的所有顏色,都由這三種色光按照不同的比例混合而成的。
小墨:這個跟繪畫的時候調制顏料差不多。
墨博士:是的,在電腦中,RGB的所謂“多少”是指亮度,并使用整數來表示。通常情況下,RGB各有256級亮度,用數字表示為從0、1、2...直到255。注意雖然數字最高是255,但0也是數值之一,因此共256級。
使用紅綠藍的這256個數值,我們就能“調制”顏色了。比如黑色可以表示為“000”,第一個0表示Red的亮度值,第2個表示綠色的亮度值,第3個表示藍色的亮度值。
小墨:那如果是白色,就是“256256256”?
墨博士:理論上是這樣的,但是這樣寫不直觀,還容易出錯,所以最后顏色就統一成了六位的十六進制。小墨,你知道十六進制嗎?
小墨:不知道,但是我知道二進制。我們平時用的是十進制。
墨博士:十六進制是計算機中數據的一種表示方法,它由0-9,A-F組成,字母不區分大小寫。與10進制的對應關系是:0-9對應0-9;A-F對應10-15。
小墨:那大于15的十進制用十六進制如何表示呢?比如16。
墨博士:十進制是逢十進位,二進制是逢二進位,十六進制道理也一樣:逢十六進位。十進制的16用十六進制表示就是進了一,結是“10”,同理17是“11”,18是“12”,255就是“FF”。
你看,RGB的最大亮度值255對應的十六進制是“FF”,也即一種顏色最多使用六位十六進制就可以表示了,前兩位表示Red的亮度,中間兩位表示Green的亮度,后面兩位表示Blue的亮度。
小墨:那不夠兩位的怎么辦?
墨博士:不夠兩位的就前面補0,比如黑色就是“000000”,白色就是“FFFFFF”,紅色就是“FF000000”。最后前面再拼接上一個“#”號,表示這是一種顏色。
小墨:明白了,這樣的話,上面的“#F08080”就是由紅色提供F0的亮度、綠色提供80亮度、藍色也提供80亮度后混合的結果。
墨博士:是的。你能算出來這種表示方式一共能表示多少顏色嗎?
小墨:嗯……,一共能表示256乘以256再乘以256種顏色,我來用python算一下……,結果是16777216,一共一千六百多萬種顏色呀!
墨博士:是的,接下來我們就定義一個方法,用于產生一種隨機顏色,其實就是產生一個六位的十六進制字符串。代碼如下:
```
def get_color():
color = ''
colors = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F']
for i in range(6):
# 隨機0-15內的數,作為下標去取colors中的字符
index = random.randint(0, 15)
# 拼接成6位的字符串
color += colors[index]
return '#' + color
```
然后把Frame的bg參數指定為`bg=get_color()`就能取得一個隨機顏色,這樣每次程序運行就都能得到不同的顏色了,如圖10.9所示。

圖10.9 隨機顏色的四色板
> 動動手:根據四色板程序編寫九色板程序,也即窗口平分為3行3列共9塊,每塊顏色隨機。
### 10.1.5 多色板
墨博士:在4色板的基礎上,只要稍加改造這段代碼,就可以做出任意多行任意多列的多色板來。
```
frame1 = Frame(width=600 / 2, height=400 / 2, bg=get_color())
frame2 = Frame(width=600 / 2, height=400 / 2, bg=get_color())
frame3 = Frame(width=600 / 2, height=400 / 2, bg=get_color())
frame4 = Frame(width=600 / 2, height=400 / 2, bg=get_color())
frame1.grid(row=0, column=0)
frame2.grid(row=0, column=1)
frame3.grid(row=1, column=0)
frame4.grid(row=1, column=1)
```
比如想開發個九色板,那定義的Frame的寬和高要除以3:
```
frame1 = Frame(width=600 / 3, height=400 / 3, bg=get_color())
…… # 定義其他Frame,此處省略
```
再把定義好的9個Frame放入畫板中:
```
frame1.grid(row=0, column=0)
frame2.grid(row=0, column=1)
frame3.grid(row=0, column=2)
frame4.grid(row=1, column=0)
frame5.grid(row=1, column=1)
frame6.grid(row=1, column=2)
frame7.grid(row=2, column=0)
frame8.grid(row=2, column=1)
frame9.grid(row=2, column=2)
```
小墨你看,上述兩個過程做的都是相同或類似的事,對于重復性的事情,就可以考慮循環來解決。思考一下,這里應該如何用循環呢?
小墨:嗯……,從將Frame放入畫板的9條語句的row和column的值可以看出,這里適合用雙重for循環。外層循環循環3次,內層循環也循環3次。
```
for i in range(3):
for j in range(3):
frame = Frame(width=600 / 3, height=400 / 3, bg=get_color())
frame.grid(row=i, column=j)
```
墨博士:將你的這段程序中的行數和列數換成變量,就能變成任意多行任意多列的多色板了。
```
# 定義行數
row_num = 4
# 定義列數
column_num = 3
# 循環創建Frame,并指定其位置
for i in range(row_num):
for j in range(column_num):
frame = Frame(width=600 / column_num, height=400 / row_num, bg=get_color())
frame.grid(row=i, column=j)
```
注意程序中Frame的寬度是600除以列數,高度是400除以行數,這個別弄混了。
運行,結果如圖10.10所示。

圖10.10 一個4行3列的色板
小墨:博士,你看我做了個20行20列的,效果如圖10.11所示。

圖 10.11 20行20列的色板
為什么和你最初展示的不一樣呢?色塊與色塊之間沒有白線分割。另外,這個窗口拉大之后效果如圖10.12所示,我能設置窗口大小不可變嗎?

圖10.12 窗口拉大后的效果
墨博士:如果想在色塊間有分割線,只要在調用grid方法的時候傳入padx和pady兩個參數就可以了:
```
frame.grid(row=i, column=j, padx=1, pady=1)
```
padx用于設置x軸方向色塊間的間隔,pady用于設置y軸方向上色塊間的間隔,單位都是像素。加上這兩個參數之后再運行,就能看到分割線了。不過需要注意的是,加了分割線后,分割線的寬度加上色塊的寬度就超過了畫板的寬度(高度也是),色塊可能就會被擠出去一些,這時只需調整下畫板的寬度值和高度值即可。
而對于設置窗口不可改變,可以在定義root之后,使用:
```
# 此時因為添加了分割線,就加大了寬度和高度,當然這個要根據實際情況調整
root.maxsize(width=620, height=420)
root.minsize(width=620, height=420)
```
設置root的最大大小和最小大小都是620x420,這樣窗口就不能被調整大小了。完整代碼如下:
```
from tkinter import *
import random
root = Tk()
root.title('多色板')
root.geometry('620x420+300+200')
root.maxsize(width=620, height=420)
root.minsize(width=620, height=420)
def get_color():
color = ''
colors = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F']
for i in range(6):
index = random.randint(0, 15)
color += colors[index]
return '#' + color
row_num = 10
column_num = 10
for i in range(row_num):
for j in range(column_num):
frame = Frame(width=600 / column_num, height=400 / row_num, bg=get_color())
frame.grid(row=i, column=j, padx=1, pady=1)
root.mainloop()
```
> 想一想:這段代碼中為了避免最后一行和最后一列被擠出畫板,將畫板的大小設置為了620x420,思考一下,如果不改變這里的畫板大小,如何既能添加行和列的間隔,又能不被擠出去呢?
## 10.2 二維碼生成器
墨博士:接下來我們乘勝追擊,再做個二維碼生成器,效果如圖10.13所示。

圖10.13 二維碼生成器
用戶在輸入框中輸入內容,然后點擊后面的按鈕,就生成了對應內容的二維碼。
小墨:我來掃一掃。滴~,果然是Hello World。
墨博士:想做這樣的一款小應用,首先需要知道按鈕及按鈕的點擊事件。
### 10.2.1 按鈕及點擊事件
和上面的單色板一樣,我們定義一個按鈕放在畫板上。
```
from tkinter import *
root = Tk()
root.title('按鈕')
root.geometry('300x100+300+200')
# 定義按鈕
btn = Button(root, text='點我')
# 指定按鈕的位置
btn.grid(row=0, column=0)
root.mainloop()
```
運行效果如圖10.14所示。

圖10.14 按鈕
因為這里我們并沒有指定按鈕的大小,所以它是默認大小顯示在窗口的左上角。
小墨:這個按鈕怎么點擊一點反應都沒有?
墨博士:想要有反應,就需要指明當按鈕被點擊時,程序做什么,這個通過在定義按鈕時指定“command=callback”實現。
```
from tkinter import *
root = Tk()
root.title('按鈕點擊效果')
root.geometry('300x100+300+200')
def callback():
print('hello ')
# 添加command=callback參數
btn = Button(root, text='點我', command=callback)
btn.grid(row=0, column=0)
root.mainloop()
```
這里的callback是一個函數的名字,在定義按鈕時添加“command=callback”,就表示點擊按鈕時執行callback函數。
你來試試吧小墨。
小墨:現在再點擊按鈕就會輸出hello了。
### 10.2.2 輸入框和標簽
墨博士:接下來說說二維碼生成器中的用于輸入的輸入框和用于圖片顯示的標簽怎么做。
```
from tkinter import *
root = Tk()
root.title('按鈕點擊效果')
# 輸入框
entry = Entry(root)
entry.grid(row=0, column=0)
def callback():
print('hello')
# 按鈕
btn = Button(root, text='點我', command=callback)
btn.grid(row=0, column=1)
# 標簽,用于顯示文字或圖片
label = Label(root)
label.grid(row=1, column=0, columnspan=2)
root.mainloop()
```
這段程序定義了一個輸入框Entry,放在了第1行第1列的位置,然后定義了一個按鈕Button,放在了第1行第2列的位置,也即放在了輸入框的后面。然后定義了一個標簽Label,放在了第2行第1列的位置,同時指定了一個“columnspan=2”的參數,表示這個控件橫跨2列。
程序運行結果如圖10.15所示。

圖15:輸入框、按鈕和標簽
現在我們給這套界面加點功能:輸入框中輸入任意內容,當點擊按鈕時,將輸入框中的內容顯示在下面橫跨兩列的標簽上。這需要三步來完成。
第一步,定義一個StringVar():
```
text = StringVar()
```
StringVar是tkinter內部定義的字符串變量類型,在這里用于管理按鈕或標簽上面的字符。改變StringVar,按鈕或標簽上的文字也隨之改變。
第二步,在Label標簽上加上“textvariable=text”參數,將標簽和StringVar通過textvariable參數關聯:
```
label = Label(root, textvariable=text)
```
這里的text就是第一步中定義的text。
最后,我們在按鈕的callback函數中改變StringVar的值,標簽上的文字也就隨著改變:
```
text.set(entry.get())
```
這里的entry.get()表示獲取輸入框中的內容。
完整代碼如下:
```
from tkinter import *
root = Tk()
root.title('點擊按鈕顯示輸入的內容')
entry = Entry(root)
entry.grid(row=0, column=0)
# 第一步:定義StringVar
text = StringVar()
def callback():
# 第三步:改變text的值,此時標簽跟著改變。
text.set(entry.get())
btn = Button(root, text='點我', command=callback)
btn.grid(row=0, column=1)
# 第二步:將標簽和StringVar通過textvariable參數關聯。
label = Label(root, textvariable=text)
label.grid(row=1, column=0, columnspan=2)
root.mainloop()
```
運行結果如圖10.16所示。

圖10.16 點擊按鈕顯示輸入的內容
小墨:這個和二維碼生成器很接近了,接下來要把標簽換成圖片了吧?
墨博士:是的,不過換圖片之前,我們需要先安裝一個第三方的庫。
### 10.2.3 圖片處理庫Pillow的安裝和使用
對于Python官方標準庫來說,可以直接使用或導入進來后直接使用,比如我們現在所使用的tkinter。對于第三方庫,則需要先下載安裝,再導入使用。
> 墨博士提醒:第一章中我們說過,除Python官方人員和你之外的人就是第三方,他們寫的庫就是第三方庫,你可以下載安裝后使用。
Python中提供了一個包管理工具叫pip,第三方庫的查找、下載、安裝及卸載等都可以使用它。使用方式非常簡單,在cmd窗口中敲入對應指令就行了。
對于我們的程序而言,想要把一張圖片展示在標簽上,就需要先安裝一個第三方的圖片處理庫,叫Pillow。使用pip下載并安裝Pillow只需要在cmd中輸入“pip install Pillow”就可以了,如圖10.17所示。

圖10.17 使用pip自動下載并安裝Pillow
結尾提示安裝成功。
安裝好之后就可以使用了,如下:
```
from tkinter import *
from PIL import Image
from PIL import ImageTk
root = Tk()
root.title('標簽上圖片的展示')
img = Image.open('C:/Users/Administrator/Desktop/momeimei.jpg')
img = ImageTk.PhotoImage(img)
label = Label(root, text="", image=img, width=500, height=500)
label.grid(row=0, column=0)
root.mainloop()
```
這里的第2、3行代碼就表示從Pillow庫中引入Image和ImageTk。第8、9兩行代碼就是使用Image和ImageTkinter來操作圖片,最終得到的img就表示桌面上的momeimei.jpg,這是墨妹妹的一張照片。
然后給標簽設置“image=img”參數,表示將得到的img圖片和標簽綁定到了一起。此時運行程序,結果如圖10.18所示。

圖10.18 標簽上展示圖片
### 10.2.4 二維碼庫qrcode的安裝和使用
墨博士:接下來說說Python中二維碼庫qrcode的安裝和使用。這是一個第三方庫,和Pillow一樣,需要使用pip進行下載和安裝。如圖10.19所示。

圖10.19 qrcode庫的安裝
安裝成功之后就可以來使用了:
```
import qrcode
# 將hello world生成二維碼
img2 = qrcode.make('hello, world')
# 將二維碼圖片保存到D盤下的qrcode文件夾下,命名為hello.png
img2.save('D:\\qrcode\\hello.png')
```
運行效果如圖10.20所示。

圖10.20 生成的二維碼圖片
### 10.2.5 二維碼生成器
把上面界面、按鈕事件、圖片顯示和二維碼生成等內容綜合起來,就能得到二維碼生成器了。代碼如下:
```
from tkinter import *
from PIL import Image
from PIL import ImageTk
import qrcode
root = Tk()
root.title('二維碼生成器')
entry = Entry(root, width=60)
entry.grid(row=0, column=0)
def callback():
# 獲取輸入的內容
text_input = entry.get()
# 將輸入的內容生成二維碼
img_new = qrcode.make(text_input)
# 保存生成的二維碼圖片
img_new.save('D:\\qrcode\\' + text_input + '.png')
# 處理成標簽能使用的類型
img_new = Image.open('D:\\qrcode\\' + text_input + '.png')
img_new = ImageTk.PhotoImage(img_new)
# 這兩步是關鍵
label.configure(image=img_new)
label.image = img_new
btn = Button(root, text='點我', command=callback)
btn.grid(row=0, column=1)
img = qrcode.make('hello, qrcode')
img.save('D:\\qrcode\\hello.png')
img = Image.open('D:\\qrcode\\hello.png')
img = ImageTk.PhotoImage(img)
label = Label(root, text="", image=img, width=500, height=500)
label.grid(row=1, column=0, columnspan=2)
root.mainloop()
```
其中第9行輸入框定義時指定的“width=60”中的60不是指60像素,而是指輸入框中能夠輸入的字符的個數,這個也就影響了輸入框的長度。
第31-35行代碼用于在程序啟動的時候就生成了一個二維碼顯示出來,二維碼的內容是“hello qrcode”。
從13行開始的callback是點擊按鈕時執行的函數,它會獲取輸入框的內容然后生成二維碼并保存在本地,然后再將本地的二維碼顯示在標簽上。這里第24、25兩行是關鍵。24行用于將img_new和標簽關聯,25行用于將img_new替換原標簽上的圖片,這樣我們每次生成二維碼都能直接顯示出來。
這樣就完成了二維碼生成器。
## 10.3 本章小結
墨博士總結:本章你學習了tkinter庫,并使用這個庫做了兩個小應用:多色板和二維碼生成器。多色板中,畫板和畫布的換算關系要計算清楚,另外就是grid布局的使用,這些你都掌握的不錯。在二維碼生成器中,主要是第三方庫Pillow和qrcode的安裝和使用,以及按鈕、輸入框、標簽等控件的使用。有了這些知識,你就能做出很多有意思的程序了。