Python 入門指南

單元 23 - Tk 的視窗元件與 V 的部分

~~學習進度表~~

Tk 具備一般常用的視窗元件,因此用 Tk 來開發小工具絕對夠用

EncryptView

M   V   C
↓      ↓
      Encrypt     EncryptController

若是桌機平台的大型軟體也可用 Tk 來開發,基本上 Python 有哪一種桌機平台的版本,就可連帶用 Tk ,但是如手機、平板、穿戴式或其他平台等等,需要看 Tk 有否支援。

這邊先來要認識有哪些視窗元件,每個圖形介面程式庫提供的元件 (component) 都差不多,不過用的名稱,也就是類別識別字 (identifier) 都不太一樣,以下是 Tk 的元件列表

類別說明
Button按鈕。
Canvas長方形區域。
Checkbutton核取按鈕。
Entry文字輸入欄。
Frame視窗。
Label文字標籤。
LabelFrame文字標籤視窗。
Listbox列表選單。
Menu選單列的下拉式選單。
MenuButton選單的選項。
Message類似 Label ,可多行。
OptionMenu下拉式的選項選單。
PaneWindow類似 Frame ,可包含其他視窗元件。
Radiobutton單選按鈕。
Scale拉桿。
Scrollbar捲軸。
Spinbox微調器
Text文字方塊。
Toplevel新增視窗。

關於 GUI 元件的英文或中文名稱,基本上各程式庫或作者的英文、中文用詞都不太一樣,,基本上這沒有什麼一致或權威的用詞,因此讀者只好自己習慣,倒是本書的用詞會保持一致的。

我們預計做出如下的 GUI

基本上「輸入:」、「輸出:」跟「訊息欄」都是文字標籤,也就是 Label ,「輸入:」及「輸出:」後面的凹陷下去的視窗元件是文字輸入欄,文字輸入欄的型態為 Entry ,下面「新建」、「載入」、「存檔」、「編碼」、「解碼」、「清除」、「拷貝」等七個是按鈕,按鈕的型態為 Button

雖說這裡只用到三種共十二個視窗元件,倒是接下來要用類別 (class) 要設計 GUI ,用類別的原因很簡單,就是把跟 GUI 相關的程式部分都打包在類別中, V 的部分用 EncryptView 類別,而 C 的部分用 EncryptController 類別,主要目的是讓整體程式碼比較好組織及維護。

然而一下子跳進 GUI 類別設計有點繁雜,這裡先列出步驟

  1. 定義繼承 (inherit)Frame類別,例如 HelloView
  2. __init__() 方法中呼叫 Frame__init__() ,然後進行相關設定,最後呼叫 createWidgets() 方法。
  3. createWidgets() 方法為自訂建立視窗元件的方法。
  4. 執行部分先建立 Tk 應用程式物件 root ,然後建立 HelloView物件,並以 root 當作 master 的參數,最後呼叫 mainloop() 方法。

以下先將上個單元的 tk_demo3.py類別改寫以資說明

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__':
  root = Tk()
  app = HelloView(master=root)
  root.mainloop()

#《程式語言教學誌》的範例程式
# https://kaiching.org/
# 檔名:hello_view.py
# 功能:示範 Python 的 Tk 應用程式
# 作者:張凱慶 */

首先,步驟 1 定義繼承Frame類別繼承的寫法就是在類別名稱之後加上小括弧,小括弧中放父類別 (superclass) 的識別字

class HelloView(Frame):

因此 HelloView 就是一種 Frame 類別,所有的視窗元件就是要加入到 HelloView 上。

步驟 2 關於 __init__() 方法的定義

def __init__(self, master=None):
  Frame.__init__(self, master)
  self.winfo_toplevel().title("Hello World!")
  self.grid()
  self.createWidgets()

注意這裡要先呼叫 Frame__init__()

Frame.__init__(self, master)

這是因為 HelloView 要發揮 Frame 的完整功能,就要先呼叫 Frame__init__() ,另外 master 需要以 Tk 應用程式物件當參數,這在底下建立 HelloView 型態的變數 app 代入

app = HelloView(master=root)

下面依序做必要的設定,像是 winfo_toplevel() 是呼叫上一層的 Tk 應用程式物件,這是因為 Frame 沒有 title() 方法設定視窗標題

self.winfo_toplevel().title("Hello World!")
self.grid()
self.createWidgets()

然後呼叫 grid() ,表示 HelloView 要用格子版面管理員,最後呼叫 createWidgets() ,這用來建立所有在 HelloView 上的視窗元件,這也是步驟 3 的部分,其定義如下

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)

HelloViewtext 屬性為文字標籤 Label ,因此往後要操作這個文字標籤都可透過 text ,然後著接下來 text 的每一個屬性都是透過字典的 key:value 方式來設定,這是因為類別屬性預設可用字典的方式存取。

最後執行部分也就是步驟 4 ,先建立 Tk 應用程式物件 root ,再建立 HelloView物件 app ,並以 rootHelloView()參數,最後 root 再呼叫 mainloop() 方法

if __name__ == '__main__':
  root = Tk()
  app = HelloView(master=root)
  root.mainloop()

執行後會得到如下的視窗

按照同樣的步驟設計 EncryptView 類別,完整程式如下

from tkinter import *
from tkinter.ttk 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.it = Label(self)
    self.it["text"] = "輸入:"
    self.it.grid(row=0, column=0,
                 sticky=N+E)
    self.ifd = Entry(self)
    self.ifd["width"] = 60
    self.ifd.grid(row=0, column=1,
                  columnspan=6,
                  sticky=N+W)

    self.ot = Label(self)
    self.ot["text"] = "輸出:"
    self.ot.grid(row=1, column=0,
                 sticky=N+E)
    self.ofd = Entry(self)
    self.ofd["width"] = 60
    self.ofd.grid(row=1, column=1,
                  columnspan=6,
                  sticky=N+W)

    self.nb = Button(self)
    self.nb["text"] = "新建"
    self.nb.grid(row=2, column=0,
                 sticky=N+W)
    self.lb = Button(self)
    self.lb["text"] = "載入"
    self.lb.grid(row=2, column=1,
                 sticky=N+W)
    self.sb = Button(self)
    self.sb["text"] = "存檔"
    self.sb.grid(row=2, column=2,
                 sticky=N+W)
    self.eb = Button(self)
    self.eb["text"] = "編碼"
    self.eb.grid(row=2, column=3,
                 sticky=N+W)
    self.db = Button(self)
    self.db["text"] = "解碼"
    self.db.grid(row=2, column=4,
                 sticky=N+W)
    self.cb = Button(self)
    self.cb["text"] = "清除"
    self.cb.grid(row=2, column=5,
                 sticky=N+W)
    self.cb2 = Button(self)
    self.cb2["text"] = "拷貝"
    self.cb2.grid(row=2, column=6,
                  sticky=N+W)

    self.dt = Label(self)
    m = "訊息欄"
    self.dt["text"] = m
    self.dt.grid(row=3, column=0,
                 columnspan=7,
                 sticky=N)

# GUI 執行部分
if __name__ == '__main__':
  root = Tk()
  app = EncryptView(master=root)
  root.mainloop()

#《程式語言教學誌》的範例程式
# https://kaiching.org/
# 檔名:encrypt_view.py
# 功能:示範 Python 的 Tk 應用程式
# 作者:張凱慶 */

這邊多引入 tkinter.ttk ,這是因為會用到 tkinter.ttk 的樣式

from tkinter.ttk import *

此外,部分跨多行的視窗元件在呼叫 grid() 方法時多做了一些設定

self.ifd.grid(row=0, column=1,
              columnspan=6,
              sticky=N+W)

columnspan 為跨多少行,而 sticky 設定視窗元件在格子中的對齊方式。

程式執行結果如下

EncryptView 類別是純粹的 V ,因此按按鈕並不會有動作,在下一單元介紹 C 及加入 command 屬性的設定,這樣按按鈕才會有反應。

中英文術語對照
元件component
類別class
識別字identifier
繼承inherit
父類別superclass
重點整理
1. Tk 的視窗元件包括各種按鈕、文字輸入欄、文字標籤、拉桿、捲軸、文字方塊等等。
2. EncryptView 類別預計要有 3 個文字標籤、 2 的文字輸入欄及 7 個按鈕。
3. 利用類別設計 Tk 的 GUI ,首先定義繼承自 Frame 的類別,然後在 __init__() 方法中呼叫 Frame__init__() ,接著定義 createWidgets() 方法逐一建立視窗中的元件。
問題與討論
1. Tk 有哪些視窗元件?常用軟體如記事本、瀏覽器等等,用了哪些視窗元件呢?
2. 利用 Tk 的 GUI 類別設計步驟為何?又為什麼要改用類別設計?
練習
1. 承接上一個單元的 tk_demo3.py ,寫一個新程式 hello_view2.py ,改成用 HelloView 類別設計 GUI。
2. 承接上一個單元的 game_demo.py 寫一個新程式 game_view.py ,改成用 GameView 類別設計 GUI 。

上一頁 單元 22 - GUI 的基本概念與 MVC 模式
回 Python 入門指南首頁
下一頁 單元 24 - C 的部分與設定 command
回 Python 教材首頁
回程式語言教材首頁