Python 入門指南 5.0
單元 31 - Tk 的視窗元件與 V 的部分
Tk 具備一般常用的視窗元件,因此用 Tk 來開發小工具絕對夠用
↑
M V C
↓ ↓
Encrypt EncryptController
若是桌機平台的大型軟體也可用 Tk 來開發,基本上 Python 有哪一種桌機平台的版本,就可連帶用 Tk ,但是如手機、平板、穿戴式或其他平台等等,需要看該平台的 Python 版本有否支援 Tk 。
這邊先來要認識有哪些視窗元件,每個圖形介面程式庫提供的元件 (component) 都差不多,不過用的名稱,也就是類別的識別字 (identifier) 都不太一樣,以下是 Tk 的元件列表
類別 | 說明或常見中文名稱 |
---|---|
Button | 按鈕。 |
Canvas | 長方形繪圖區域。 |
Checkbutton | 核取按鈕。 |
Combobox | 下拉式單選選單。 |
Entry | 單行文字輸入欄位。 |
Frame | 可容納其他視窗元件的長方形區域類別。 |
Label | 文字標籤。 |
Listbox | 單選選單。 |
Menu | 選單。 |
Progressbar | 進度條。 |
Radiobuttion | 單選按鈕。 |
Scale | 滑動條。 |
Scrollbar | 卷軸。 |
Separator | 分隔線。 |
Spinbox | 微調選單。 |
Style | 設定樣式或主題的類別。 |
Text | 多行文字輸入欄位。 |
Toplevel | 新增視窗的類別。 |
關於 GUI 元件的英文或中文名稱,基本上各程式庫或作者的英文、中文用詞都不太一樣,,基本上這沒有什麼一致或權威的用詞,因此讀者只好自己習慣,倒是本書的用詞會保持一致的。
我們預計做出如下的 GUI
基本上「輸入:」、「輸出:」跟「訊息欄」都是文字標籤,也就是 Label ,「輸入:」及「輸出:」後面的凹陷下去的視窗元件是文字輸入欄,文字輸入欄的型態為 Entry ,下面「新建」、「載入」、「存檔」、「編碼」、「解碼」、「清除」、「拷貝」等七個是按鈕,按鈕的型態為 Button 。
雖說這裡只用到三種共十二個視窗元件,倒是接下來要用類別 (class) 要設計 GUI ,用類別的原因很簡單,就是把跟 GUI 相關的程式部分都打包在類別中, V 的部分用 EncryptView 類別,而 C 的部分用 EncryptController 類別,主要目的是讓整體程式碼比較好組織及維護。
然而一下子跳進 GUI 類別設計有點繁雜,這裡先列出步驟
- 定義繼承 (inherit) 自 Frame 的類別,例如 HelloView ;
- 在 __init__() 方法中呼叫 Frame 的 __init__() ,然後進行相關設定,最後呼叫 createWidgets() 方法;
- 定義 createWidgets() 方法,其為自訂建立視窗元件的方法;
- 執行部分先建立 Tk 應用程式物件 root ,然後建立 HelloView 的物件,並以 root 當作 master 的參數,最後呼叫 mainloop() 方法。
以下先將上個單元的 tk_demo3.py 用類別改寫以資說明
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | # 從標準程式庫引入 Tk
from tkinter import *
# Hello 的 View 類別
class HelloView(Frame):
# 建構子設定初值
def __init__(self, master=None):
# 呼叫父類別的建構子
Frame.__init__(self, master)
# 設定視窗標題
self.winfo_toplevel().title("Hello World!")
# 使用格子版面管理員
self.grid()
# 呼叫建立視窗元件的方法
self.createWidgets()
# 建立視窗元件
def createWidgets(self):
# 建立文字輸入標籤
self.text = Label(self)
# 設定文字輸入標籤的文字
self.text["text"] = "Hello World!"
# 設定文字輸入標籤的寬度
self.text["width"] = "30"
# 設定文字輸入標籤的高度
self.text["height"] = "5"
# 設定文字輸入標籤的背景顏色
self.text["bg"] = "black"
# 設定文字輸入標籤的文字顏色
self.text["fg"] = "white"
# 設定文字輸入標籤在格子的位置
self.text.grid(row=0, column=0)
# GUI 執行部分
if __name__ == '__main__':
# 建立 Tk 應用物件
root = Tk()
# 建立視窗物件
app = HelloView(master=root)
# 呼叫維持視窗運作的 mainloop()
root.mainloop()
# 檔名: hello_view.py
# 說明:《Python入門指南》的範例程式
# 網站: http://kaiching.org
# 作者: 張凱慶
# 時間: 2023 年 6 月
|
首先,步驟 1 定義繼承自 Frame 的類別,繼承的寫法就是在類別名稱之後加上小括弧,小括弧中放父類別 (superclass) 的識別字
5 | class HelloView(Frame):
|
因此 HelloView 就是一種 Frame 類別,所有的視窗元件就是要加入到 HelloView 上。
步驟 2 關於 __init__() 方法的定義
7 9 11 13 15 | def __init__(self, master=None):
Frame.__init__(self, master)
self.winfo_toplevel().title("Hello World!")
self.grid()
self.createWidgets()
|
注意這裡要先呼叫 Frame 的 __init__()
9 | Frame.__init__(self, master)
|
這是因為 HelloView 要發揮 Frame 的完整功能,就要先呼叫 Frame 的 __init__() ,另外 master 需要以 Tk 應用程式物件當參數,這在底下建立 HelloView 型態的變數 app 代入
39 | app = HelloView(master=root)
|
下面依序做必要的設定,像是 winfo_toplevel() 是呼叫上一層的 Tk 應用程式物件,這是因為 Frame 沒有 title() 方法設定視窗標題
11 13 15 | self.winfo_toplevel().title("Hello World!")
self.grid()
self.createWidgets()
|
然後呼叫 grid() ,表示 HelloView 要用格子版面管理員,最後呼叫 createWidgets() ,這用來建立所有在 HelloView 上的視窗元件,這也是步驟 3 的部分,其定義如下
18 20 22 24 26 28 30 32 | def createWidgets(self):
self.text = Label(self)
self.text["text"] = "Hello World!"
self.text["width"] = "30"
self.text["height"] = "5"
self.text["bg"] = "black"
self.text["fg"] = "white"
self.text.grid(row=0, column=0)
|
HelloView 的 text 屬性 (attribute) 為文字標籤 Label ,因此往後要操作這個文字標籤都可透過 text ,然後著接下來 text 的每一個屬性都是透過字典的 key:value 方式來設定,這是因為類別的屬性預設可用字典的方式存取。
createWidgets() 是定義所有視窗元件的方法,單獨設計成一個方法 (method) 是為了讓 __init__() 更簡潔,雖然說也可以把定義視窗元件的部分都寫在 __init__() 中,但是這樣子 __init__() 就會過長,不易閱讀。
最後執行部分也就是步驟 4 ,先建立 Tk 應用程式物件 root ,再建立 HelloView 的物件 app ,並以 root 當 HelloView() 的參數 (parameter) ,最後 root 再呼叫 mainloop() 方法
35 37 39 41 | if __name__ == '__main__':
root = Tk()
app = HelloView(master=root)
root.mainloop()
|
執行後會得到如下的視窗
按照同樣的步驟設計 EncryptView 類別,完整程式如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | # 從標準程式庫引入 Tk
from tkinter import *
# Encrypt 的 View 類別
class EncryptView(Frame):
# 建構子設定初值
def __init__(self, master=None):
# 呼叫父類別的建構子
Frame.__init__(self, master)
# 設定視窗標題
self.winfo_toplevel().title("編密碼小工具")
# 使用格子版面管理員
self.grid()
# 呼叫建立視窗元件的方法
self.createWidgets()
# 建立所有視窗元件
def createWidgets(self):
# 建立文字輸入標籤
self.input_text = Label(self)
# 設定文字輸入標籤的文字
self.input_text["text"] = "輸入:"
# 設定文字輸入標籤在格子的位置
self.input_text.grid(row=0, column=0)
# 建立文字輸入欄位
self.input_field = Entry(self)
# 設定文字輸入欄位的寬度
self.input_field["width"] = 77
# 設定文字輸入欄位在格子的位置
self.input_field.grid(row=0, column=1,
columnspan=6)
# 設定文字輸出標籤
self.output_text = Label(self)
# 設定文字輸出標籤的文字
self.output_text["text"] = "輸出:"
# 設定文字輸出標籤格子的位置
self.output_text.grid(row=1, column=0)
# 設定文字輸出欄位
self.output_field = Entry(self)
# 設定文字輸出欄位的寬度
self.output_field["width"] = 77
# 設定文字輸出欄位在格子的位置
self.output_field.grid(row=1, column=1,
columnspan=6)
# 設定新建按鈕在格子的位置
self.new_button = Button(self)
# 設定新建按鈕的文字
self.new_button["text"] = "新建"
# 設定新建按鈕在格子的位置
self.new_button.grid(row=2, column=0)
# 設定載入按鈕
self.load_button = Button(self)
# 設定載入按鈕的文字
self.load_button["text"] = "載入"
# 設定載入按鈕在格子的位置
self.load_button.grid(row=2, column=1)
# 設定存檔按鈕
self.save_button = Button(self)
# 設定存檔按鈕的文字
self.save_button["text"] = "存檔"
# 設定存檔按鈕在格子的位置
self.save_button.grid(row=2, column=2)
# 設定編碼按鈕
self.encode_button = Button(self)
# 設定編碼按鈕的文字
self.encode_button["text"] = "編碼"
# 設定編碼按鈕在格子的位置
self.encode_button.grid(row=2, column=3)
# 設定解碼按鈕
self.decode_button = Button(self)
# 設定解碼按鈕的文字
self.decode_button["text"] = "解碼"
# 設定解碼按鈕在格子的位置
self.decode_button.grid(row=2, column=4)
# 設定清除按鈕
self.copy_button = Button(self)
# 設定清除按鈕的文字
self.copy_button["text"] = "清除"
# 設定清除按鈕在格子的位置
self.copy_button.grid(row=2, column=5)
# 設定拷貝按鈕
self.clear_button = Button(self)
# 設定拷貝按鈕的文字
self.clear_button["text"] = "拷貝"
# 設定拷貝按鈕在格子的位置
self.clear_button.grid(row=2, column=6)
# 設定訊息欄文字標籤
self.display_text = Label(self)
# 設定訊息欄文字標籤的文字
self.display_text["text"] = "訊息欄"
# 設定訊息欄文字標籤在格子的位置
self.display_text.grid(row=3, column=0,
columnspan=7)
# GUI 執行部分
if __name__ == '__main__':
# 建立 Tk 應用物件
root = Tk()
# 建立視窗物件
app = EncryptView(master=root)
# 呼叫維持視窗運作的 mainloop()
root.mainloop()
# 檔名: encrypt_view01.py
# 說明:《Python入門指南》的範例程式
# 網站: http://kaiching.org
# 作者: 張凱慶
# 時間: 2023 年 6 月
|
注意到三個地方,先是第 31 行及第 44 行
31 44 | columnspan=6)
columnspan=6)
|
然後是第 93 行
93 | columnspan=7)
|
columnspan 為延伸多少行,這是說文字輸入欄位及文字輸出欄位延伸 6 行,最底下訊息欄文字標籤則是延伸 7 行。
注意這裡 column 為行,直為行, row 為列,橫為列。
程式執行結果如下
EncryptView 類別是純粹的 V ,完全採 Tk 預設的樣式,按下按鈕也沒有任何像是按下動畫的反應,下一個單元我們加入 ttk 的主題樣式設定,讓這個「編密碼小工具」更美觀點。
中英文術語對照 | |
---|---|
屬性 | attribute |
元件 | component |
類別 | class |
識別字 | identifier |
繼承 | inherit |
方法 | method |
參數 | parameter |
父類別 | superclass |
重點整理 |
---|
1. Tk 的視窗元件包括各種按鈕、文字輸入欄、文字標籤、拉桿、捲軸、文字方塊等等。 |
2. EncryptView 類別預計要有 3 個文字標籤、 2 的文字輸入欄及 7 個按鈕。 |
3. 利用類別設計 Tk 的 GUI ,首先定義繼承自 Frame 的類別,然後在 __init__() 方法中呼叫 Frame 的 __init__() ,接著定義 createWidgets() 方法逐一建立視窗中的元件。 |
問題與討論 |
---|
1. Tk 有哪些視窗元件?常用軟體如記事本、瀏覽器等等,用了哪些視窗元件呢? |
2. 利用 Tk 的 GUI 類別設計步驟為何?又為什麼要改用類別設計? |
練習 |
---|
1. 寫一個程式 exercise3101.py ,利用 Tk 及格子版面管理員,設計從上到下依序為 Entry 、 Button 、 Label 的視窗。 參考程式碼 |
2. 寫一個程式 exercise3102.py ,利用 Tk 及格子版面管理員,設計從上到下依序為 Text 、 Button 、 Label 的視窗。 參考程式碼 |
3. 寫一個程式 exercise3103.py ,利用 Tk 及格子版面管理員,設計從上到下依序為 4 個 Checkbutton 、 Label 的視窗。 參考程式碼 |
4. 寫一個程式 exercise3104.py ,利用 Tk 及格子版面管理員,設計從上到下依序為 ttk 的 Combobox 、 Label 的視窗。 參考程式碼 |
5. 寫一個程式 exercise3105.py ,利用 Tk 及格子版面管理員,設計從上到下依序為 Listbox 、 Label 的視窗,其中 Listbox 需要用 insert() 方法插入 4 個選項。 參考程式碼 |
6. 寫一個程式 exercise3106.py ,利用 Tk 及格子版面管理員,設計從上到下依序為 4 個 Radiobutton 、 Label 的視窗,其中 Radiobutton 要額外設定 "text" 、 "value" 、 "variable" 。 參考程式碼 |
7. 寫一個程式 exercise3107.py ,利用 Tk 及格子版面管理員,設計從上到下依序為 Spinbox 、 Label 的視窗。 參考程式碼 |
8. 寫一個程式 exercise3108.py ,利用 Tk 及格子版面管理員,設計從上到下依序為 Progressbar 、 Scale 的視窗,其中 Scale 要額外設定 "orient"。 參考程式碼 |
9. 寫一個程式 exercise3109.py ,利用 Tk 及格子版面管理員,設計從上到下依序為 Canvas 、 Button 的視窗,其中 Canvas 要額外設定 "width" 及 "height" ,也可以設定 "bg" 。 參考程式碼 |
10. 寫一個程式 exercise3110.py ,利用 Tk 及格子版面管理員,設計從上到下依序為 Toplevel 、 Button 的視窗。 參考程式碼 |
回 Python 入門指南 5.0 首頁
unit-32-layout-and-styling-of-window-widgets下一頁 單元 32 - 視窗元件的排版及樣式主題