Python 入門指南 5.0
單元 33 - C 的部分與設定 command
V 的部分已完成,現在進入到 C 的部分
↑
M V C
↓ ↓
Encrypt EncryptController
這裡繼續回頭討論一下 V 的部分,其實絕大多數的 GUI 程式庫 (library) 在 V 的部分會改採 XML 或類似 XML 的方式設計,例如知名的 Qt 採 QML , JavaFX 採 FXML , Python 另一個知名的第三方程式庫 Kivy 用 KV language ,並且大都有圖形化的設計工具 (designer) ,用圖形化的設計工具製作 V 的部分就簡單多了,那問題來了, Tk 有沒有這方面的工具呢?
答案是有的,不過那是第三方團隊開發的工具,例如下圖為 Pygubu 的設計工具
Pygubu 為開放原始碼的軟體,其在 GitHub 的網址為 https://github.com/alejandroautalan/pygubu ,另一個知名第三方開發工具為 Page ,下載網址為 http://page.sourceforge.net/ 。
Pygubu 就會產生副檔名 .ui 的 XML 檔案,以下為用文字編輯器 Atom 開啟上圖製作的 view.ui
至於如何下載安裝及在自己寫的 Python 程式載入使用 .ui 檔案,請參考其 GitHub 網頁的說明。
那為什麼我們不用 Pygubu 這樣的設計工具呢?原因其一為 Python 官方沒有納入,往後版本不見得會隨 Python 的版本同步更新,其二為需要額外介紹 Pygubu 的介面以及載入使用,這會額外加入其他的篇章,另外 Pygubu 直接用格子版面管理員,這雖然也是我們採用的版面管理員,可是網路上大量的 Tk 範例不見得會用格子版面管理員,因此有需要認識其他兩種版面管理員。
下面開始介紹 C 的部分,有新建、開啟、儲存、編碼、解碼、清除及拷貝等七個按鈕,這裡,先不急著實作七個按鈕的方法 (method) ,因為每個方法都還牽涉到一些其他概念,我們改成先寫一個發展中的版本,讓每個按鈕都有功能,卻是相對簡化許多的功能。
簡單說,就是先讓按鈕做簡單的事情就好,那要什麼樣的事情呢?由於 self.display_text 是狀態列,本來按下按鈕就要顯示訊息到狀態列,那我們就先讓按下按鈕顯示這是什麼按鈕就好了,這邊先提供 EncryptController 的開發中版本
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 | # 從標準程式庫 tkinter 引入 Tk
from tkinter import Tk
# 縱定義模組 encrypt_view 引入 EncryptView
from encrypt_view import EncryptView
# Encrypt 的 Controller 類別
class EncryptController:
# 設定初值
def __init__(self):
# 設定 EncryptView 屬性
self.app = EncryptView(master=Tk())
# 設定按鈕的事件連結方法
self.app.new_button["command"] = self.new_method
self.app.load_button["command"] = self.load_method
self.app.save_button["command"] = self.save_method
self.app.encode_button["command"] = self.encode_method
self.app.decode_button["command"] = self.decode_method
self.app.clear_button["command"] = self.clear_method
self.app.copy_button["command"] = self.copy_method
# 呼叫維持視窗運作的 mainloop()
self.app.mainloop()
# 按下新建按鈕的事件
def new_method(self):
# 顯示按下按鈕觸發的事件
self.app.display_text["text"] = "觸發新建按鈕的事件。"
# 按下載入按鈕的事件
def load_method(self):
# 顯示按下按鈕觸發的事件
self.app.display_text["text"] = "觸發載入按鈕的事件。"
# 按下儲存按鈕的事件
def save_method(self):
# 顯示按下按鈕觸發的事件
self.app.display_text["text"] = "觸發儲存按鈕的事件。"
# 按下編碼按鈕的事件
def encode_method(self):
# 顯示按下按鈕觸發的事件
self.app.display_text["text"] = "觸發編碼按鈕的事件。"
# 按下解碼按鈕的事件
def decode_method(self):
# 顯示按下按鈕觸發的事件
self.app.display_text["text"] = "觸發解碼按鈕的事件。"
# 按下清除按鈕的事件
def clear_method(self):
# 顯示按下按鈕觸發的事件
self.app.display_text["text"] = "觸發清除按鈕的事件。"
# 按下拷貝按鈕的事件
def copy_method(self):
# 顯示按下按鈕觸發的事件
self.app.display_textsx ["text"] = "觸發拷貝按鈕的事件。"
# GUI 執行部分
if __name__ == '__main__':
#
app = EncryptController()
# 檔名: encrypt_controller01.py
# 說明:《Python入門指南》的範例程式
# 網站: http://kaiching.org
# 作者: 張凱慶
# 時間: 2023 年 6 月
|
請將 encrypt_controller01.py 放到跟 encrypt_view 相同的資料夾中。
先看到 import 的部分,這篇只引入兩個必要的類別 (class) ,分別是 Tk 及 EncryptView
2 4 | from tkinter import Tk
from encrypt_view import EncryptView
|
這是因為視窗運作需要 Tk 應用程式物件,也需要替 EncryptController 設定 EncryptView 型態的屬性。
下面繼續看到 __init__() 方法的定義
9 11 13 14 15 16 17 18 19 21 | def __init__(self):
self.app = EncryptView(master=Tk())
self.app.new_button["command"] = self.new_method
self.app.load_button["command"] = self.load_method
self.app.save_button["command"] = self.save_method
self.app.encode_button["command"] = self.encode_method
self.app.decode_button["command"] = self.decode_method
self.app.clear_button["command"] = self.clear_method
self.app.copy_button["command"] = self.copy_method
self.app.mainloop()
|
這裡屬性 (attribute) app 為 EncryptView 型態 (type) 的物件 (object) ,因此 app 就是一個 Frame
11 | self.app = EncryptView(master=Tk())
|
然後透過 app 設定視窗元件的屬性 command ,例如將 new_button 的 command 設定為 self.new_method
13 | self.app.new_button["command"] = self.new_method
|
self.new_method 為 EncryptController 的方法之一,其定義如下
24 26 | def new_method(self):
self.app.display_text["text"] = "觸發新建按鈕的事件。"
|
注意這樣的分別是視窗元件在 V 中設定,視窗元件相關事件連動的方法則在 C 中設定。
其他的按鈕也依序設定, __init__() 方法最後呼叫 mainloop() ,好維持視窗顯示
21 | self.app.mainloop()
|
之前的單元 mainloop() 方法都是由 Tk 應用程式物件 root 呼叫,這裡由繼承 (inherit) 自 Frame 的 EncryptView 型態的屬性 app 呼叫,其實兩者都可呼叫,因為 app 已經用 Tk 應用程式物件當參數 (parameter) 建立。
來執行看看囉!以下是點擊編碼按鈕的結果
繼續點擊清除按鈕
結果都 OK !接下來,我們要開始整合 Encrypt 類別了。
中英文術語對照 | |
---|---|
屬性 | attribute |
類別 | class |
設計工具 | designer |
繼承 | inherit |
方法 | method |
物件 | object |
參數 | parameter |
型態 | type |
重點整理 |
---|
1. Pygubu 是視覺化的 Tk 視窗設計工具。 |
2. Tk 的視窗元件由設定 command ,來指定與元件連動的方法。 |
3. 我們先寫一個發展中的版本,設定按下按鈕後在訊息欄顯示按鈕名稱。 |
問題與討論 |
---|
1. 為什麼每個按鈕都要有專屬方法?可以幾個按鈕共用一個方法,或是某個按鈕不跟方法連結嗎? |
2. 除了顯示按鈕名稱,還有什麼簡單事情是可以先給按鈕做的? |
練習 |
---|
1. 承接單元 32 的練習 1 ,將新程式寫在 exercise3301.py 中,替按鈕加入印出 Entry 輸入的功能。 參考程式碼 |
2. 承接單元 32 的練習 2 ,將新程式寫在 exercise3302.py 中,替按鈕加入計算行數功能。 參考程式碼 |
3. 承接單元 32 的練習 3 ,將新程式寫在 exercise3303.py 中,替 Checkbutton 加入即時勾選顯示選項在 Label 的功能。 參考程式碼 |
4. 承接單元 32 的練習 4 ,將新程式寫在 exercise3304.py 中,替 Combobox 加入即時選擇的選項顯示在 Label 的功能。 參考程式碼 |
5. 承接單元 32 的練習 5 ,將新程式寫在 exercise3305.py 中,替 Listbox 加入即時選擇的選項顯示在 Label 的功能。 參考程式碼 |
6. 承接單元 32 的練習 6 ,將新程式寫在 exercise3306.py 中,替 Radiobutton 加入即時選擇的選項顯示在 Label 的功能。 參考程式碼 |
7. 承接單元 32 的練習 7 ,將新程式寫在 exercise3307.py 中,替 Spinbox 加入即時取得的值顯示在 Label 的功能。 參考程式碼 |
8. 承接單元 32 的練習 8 ,將新程式寫在 exercise3308.py 中,替 Scale 加入即時取得的進度值顯示在 Progressbar 的功能。 參考程式碼 |
9. 承接單元 32 的練習 9 ,將新程式寫在 exercise3309.py 中,替按鈕加入在 Canvas 畫出直線的功能。 參考程式碼 |
10. 承接單元 32 的練習 10 ,將新程式寫在 exercise3310.py 中,替按鈕加入跳出提示視窗的功能。 參考程式碼 |