Python 入門指南 5.0

單元 33 - C 的部分與設定 command

~~學習進度表~~

V 的部分已完成,現在進入到 C 的部分

EncryptView

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) ,分別是 TkEncryptView

 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) appEncryptView 型態 (type) 的物件 (object) ,因此 app 就是一個 Frame

11
        self.app = EncryptView(master=Tk())

然後透過 app 設定視窗元件的屬性 command ,例如將 new_buttoncommand 設定為 self.new_method

13
        self.app.new_button["command"] = self.new_method

self.new_methodEncryptController 的方法之一,其定義如下

24
26
    def new_method(self):
        self.app.display_text["text"] = "觸發新建按鈕的事件。"

注意這樣的分別是視窗元件在 V 中設定,視窗元件相關事件連動的方法則在 C 中設定。

其他的按鈕也依序設定, __init__() 方法最後呼叫 mainloop() ,好維持視窗顯示

21
        self.app.mainloop()

之前的單元 mainloop() 方法都是由 Tk 應用程式物件 root 呼叫,這裡由繼承 (inherit) 自 FrameEncryptView 型態的屬性 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 中,替按鈕加入跳出提示視窗的功能。 參考程式碼

上一頁 單元 32 - 視窗元件的排版及樣式主題
回 Python 入門指南 5.0 首頁
下一頁 單元 34 - 整合 Encrypt 類別
回 Python 教材首頁
回程式語言教材首頁