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 的部分,有新建、開啟、儲存、編碼、解碼、清除及拷貝等七個按鈕,這裡,先不急著實作七個按鈕的方法,因為每個方法都還牽涉到一些其他概念,我們改成先寫一個發展中的版本,讓每個按鈕都有功能,卻是相對簡化許多的功能。
簡單說,就是先讓按鈕做簡單的事情就好,那要什麼樣的事情呢?由於 self.dt 是提示訊息欄,本來按下按鈕就要顯示訊息到提示訊息欄,那我們就先讓按下按鈕顯示這是什麼按鈕就好了,這邊先提供 EncryptController 的開發中版本
from tkinter import Tk
from encrypt_view import EncryptView
# Encrypt 的 Controller 類別
class EncryptController:
# 設定初值
def __init__(self):
self.app = EncryptView(master=Tk())
self.app.nb["command"] = self.nm
self.app.lb["command"] = self.lm
self.app.sb["command"] = self.sm
self.app.eb["command"] = self.em
self.app.db["command"] = self.dm
self.app.cb["command"] = self.cm
self.app.cb2["command"] = self.cm2
self.app.mainloop()
# 按下新建按鈕的事件
def nm(self):
self.app.dt["text"] = "觸發新建按鈕的事件。"
# 按下載入按鈕的事件
def lm(self):
self.app.dt["text"] = "觸發載入按鈕的事件。"
# 按下儲存按鈕的事件
def sm(self):
self.app.dt["text"] = "觸發儲存按鈕的事件。"
# 按下編碼按鈕的事件
def em(self):
self.app.dt["text"] = "觸發編碼按鈕的事件。"
# 按下解碼按鈕的事件
def dm(self):
self.app.dt["text"] = "觸發解碼按鈕的事件。"
# 按下清除按鈕的事件
def cm(self):
self.app.dt["text"] = "觸發清除按鈕的事件。"
# 按下拷貝按鈕的事件
def cm2(self):
self.app.dt["text"] = "觸發拷貝按鈕的事件。"
# GUI 執行部分
if __name__ == '__main__':
app = EncryptController()
#《程式語言教學誌》的範例程式
# http://kaiching.org/
# 檔名:encrypt_controller1.py
# 功能:示範 Python 的 Tk 應用程式
# 作者:張凱慶 */
請將 encrypt_controller1.py 放到跟 encrypt_view 相同的資料夾中。
先看到 import 的部分,這篇只引入兩個必要的類別 (class) ,分別是 Tk 及 EncryptView
from tkinter import Tk
from encrypt_view import EncryptView
這是因為視窗運作需要 Tk 應用程式物件,也需要替 EncryptController 設定 EncryptView 型態的屬性。
下面繼續看到 __init__() 方法的定義
# 設定初值
def __init__(self):
self.app = EncryptView(master=Tk())
self.app.nb["command"] = self.nm
self.app.lb["command"] = self.lm
self.app.sb["command"] = self.sm
self.app.eb["command"] = self.em
self.app.db["command"] = self.dm
self.app.cb["command"] = self.cm
self.app.cb2["command"] = self.cm2
self.app.mainloop()
這裡屬性 app 為 EncryptView 型態的物件,因此 app 就是一個 Frame
self.app = EncryptView(master=Tk())
然後透過 app 設定視窗元件的屬性 command ,例如這裡將 nb 的 command 設定為 self.nm
self.app.nb["command"] = self.nm
self.nm 為 EncryptController 的方法之一,其定義如下
def nm(self):
self.app.dt["text"] = "觸發新建按鈕的事件。"
注意這樣的分別是視窗元件在 V 中設定,視窗元件相關事件連動的方法 (method) 則在 C 中設定。
其他的按鈕也依序設定, __init__() 方法最後呼叫 mainloop() ,好維持視窗顯示
self.app.mainloop()
之前的單元 mainloop() 方法都是由 Tk 應用程式物件 root 呼叫,這裡由繼承自 Frame 的 EncryptView 型態的屬性 app 呼叫,其實兩者都可呼叫,因為 app 已經用 Tk 應用程式物件當參數建立。
來執行看看囉!以下是點擊編碼按鈕的結果
繼續點擊清除按鈕
結果都 ok !接下來,我們要開始整合 Encrypt 類別了。
中英文術語對照 | |
---|---|
類別 | class |
設計工具 | designer |
程式庫 | library |
方法 | method |
重點整理 |
---|
1. Tk 的視窗元件由設定 command ,來指定與元件連動的方法。 |
2. 我們先寫一個發展中的版本,設定按下按鈕後在訊息欄顯示按鈕名稱。 |
問題與討論 |
---|
1. 為什麼每個按鈕都要有專屬方法?可以幾個按鈕共用一個方法,或是某個按鈕不跟方法連結嗎? |
2. 除了顯示按鈕名稱,還有什麼簡單事情是可以先給按鈕做的? |
練習 |
---|
1. 承接上一個單元的 hello_view2.py ,寫一個新程式 hello_controller.py ,替 HelloView 寫一個 HelloController 類別,當使用者按下按鈕後顯示 "按鈕被按" 。 |
2. 承接上一個單元的 game_view.py ,寫一個新程式 game_controller.py ,替 GameView 寫一個 GameController 類別,當使用者按下按鈕後顯示 "按鈕被按" 。 |
相關教學影片