Python可以這樣玩(7):GUI 程式設計

這一課算是一個里程碑,代表我們學會了 Python 程式語言的基礎邏輯部分,準備進入到介面的設計。



在此之前,我們所寫的程式都是命令列的程式,透過 input()print() 一行一行跟程式互動,這是一種古老的方式,現在已經進入 Windows 時代了,如果還用以前DOS的方式寫程式,有很多事情會無法達成,例如,你要寫一個計算機程式,請問如何用DOS模式來寫呢?

好消息是,Python 提供了一個好用的 GUI模組 tkinterPython IDLE 就是用 tkinter 製作的。

Hello World! For Windows

按照慣例,我們又要寫一個 Hello World 程式,創建我們第一個 Windows 視窗:
開啟一個新的檔案,輸入下面的程式碼:

from tkinter import *

my_window = Tk()
my_window.title('Hello World!')
my_window.geometry('400x100')

my_window.mainloop()

這程式分成三個部分,首先一定要 import tkinter 的所有方法,第二步透過 Tk() 函數創建一個視窗物件 my_window,然後定義其中的 title geometry ( x )。第三步就是進入視窗程式的主迴圈。

空白視窗的執行結果如下(那根羽毛其實很像台灣)


接下來,我們要將 tkinter 物件加入我們的空白視窗,tkinter 提供非常多的視窗物件,例如: ButtonLabelCanvasMenuEntry 等等等,我們就從最基本的開始。


Label 標籤

Label 是用來顯示單列文字的物件,請接著修改前面的程式碼:

from tkinter import *

my_window = Tk()
my_window.title('Hello World!')
my_window.geometry('400x100')

my_label = Label(my_window, text = 'Hello Windows!', bg = 'yellow')
my_label.pack()

my_window.mainloop()

要在視窗上面建置物件有兩個步驟,首先透過 Label() 創建物件並傳入必要的參數,然後使用 pack() 布局方式將此物件放置在視窗裡。pack() 是最基本的布局方式,就是由上到下依序放置。結果如下:


Entry 文字方塊

前面的 Label 可以用來輸出文字,但是如何讓使用者輸入文字呢?就必須使用 Entry,修改程式如下:

from tkinter import *

my_window = Tk()
my_window.title('Hello World!')
my_window.geometry('400x100')

my_label = Label(my_window, text = 'Hello Windows!', bg = 'yellow')
my_label.pack()

my_enter = Entry(my_window, width = 20)
my_enter.pack()

my_window.mainloop()

結果如下:


到目前為止,我們已經可以顯示字串,以及輸入字串,但是什麼事情都不能做,因為我們還沒有處理輸入完畢之後要執行的命令。這個命令通常會在 Button 裡面處理。所以接下來,我們來介紹最重要的部分,Button


事件驅動程式設計

設計視窗應用程式,屬於事件驅動程式設計。還記得在前面的主程式裡面,有一個 mainloop(),這個函數就是讓我們的視窗進入一個等待事件的迴圈,當我們在視窗上面的某個物件上,例如按鈕,用滑鼠點了一下的時候,這個迴圈就會偵測到一個 mouse click 的事件,然後再按照我們替這個事件事先設計好的 command 來執行。

Button 按鈕

按鈕是最常用來接受事件的物件,我們現在將前面的視窗程式,設計成讓使用者在 Entry 裡面輸入文字,按下按鈕之後,就在 Label 中顯示所輸入的文字。程式碼如下:


裡面所有修改的部分,我都做了備註,方便閱讀,執行的結果如下:


加法器:




隨堂測驗

建立一個加法計算機
輸出結果如上:

from ___________ import *

my_window = ______
my_window._______('小計算機')
my_window.__________('400x200')

# 加入一個字串變數,用來控制 Label textvariable
label_var = _____________
label_var.set('0')

# 原本的 text 改成 textvariable
my_label = Label(___________, ______________ = label_var,
width = 20, bg = 'yellow')
my_label.__________

my_label1 = Label(__________, _____ = '請輸入第一個數字')
my_label1.pack()

my_enter1 = Entry(__________, width = 20)
my_enter1.pack()

my_label2 = Label(__________, _____ = '請輸入第二個數字')
my_label2.pack()

my_enter2 = Entry(__________, width = 20)
my_enter2.pack()

# 新增一個 Button command 的處理函數
def click_add():
    label_var.set(int(my_enter1.get()) + int(my_enter2.get()))

# 加入 Button 物件
my_button = Button(________, _____ = '相加', ________ = _________)
my_button.pack()

# 進入事件迴圈
my_window.mainloop()

messagebox 訊息框

所謂事件驅動程式設計,就是指程式執行之後,會在 mainloop() 迴圈裡面等待事件發生,但是當訊息框這種視窗出現的時候,程式就會跳到訊息框的事件迴圈裡面,除非你做指定的動作,否則不會跳回主迴圈。

訊息框通常用於顯示必須讓使用者注意的文字,除非使用者看到,否則程式就會停在訊息框裡面,我們把第一個 window.py 修改一下,多加一個按鈕,使用者按下按鈕之後出現訊息框,程式執行畫面如下圖:


按下訊息框按鈕:


程式碼如下,我們換了一種 import 寫法,讓程式更具可讀性:

import tkinter
import tkinter.messagebox

my_window = tkinter.Tk()
my_window.title('Hello World!')
my_window.geometry('400x100')

# 加入一個字串變數,用來控制 Label textvariable
label_var = tkinter.StringVar()
label_var.set('Hello Windows!')

# 原本的 text 改成 textvariable
my_label = tkinter.Label(my_window, textvariable = label_var, bg = 'yellow')
my_label.pack()

my_enter = tkinter.Entry(my_window, width = 20)
my_enter.pack()

def click_me():
    label_var.set(my_enter.get())

my_button1 = tkinter.Button(my_window, text = 'Click Me!', command = click_me)
my_button1.pack()

def show_message():
    tkinter.messagebox.showinfo(title = '訊息框', message = '請按下OK按鈕')
                               
# 多加一個 Button 物件
my_button2 = tkinter.Button(my_window, text = '訊息框', command = show_message)
my_button2.pack()

# 進入事件迴圈
my_window.mainloop()

要使用messagebox,一定要 import tkinter 以及 import tkinter.messagebox,兩者缺一不可,我們可以用下面的方式簡化程式:

import tkinter as tk
import tkinter.messagebox as tm

my_window = tk.Tk()
my_window.title('Hello World!')
my_window.geometry('400x100')

# 加入一個字串變數,用來控制 Label textvariable
label_var = tk.StringVar()
label_var.set('Hello Windows!')

# 原本的 text 改成 textvariable
my_label = tk.Label(my_window, textvariable = label_var, bg = 'yellow')
my_label.pack()

my_enter = tk.Entry(my_window, width = 20)
my_enter.pack()

def click_me():
    label_var.set(my_enter.get())

my_button1 = tk.Button(my_window, text = 'Click Me!', command = click_me)
my_button1.pack()

def show_message():
    tm.showinfo(title = '訊息框', message = '請按下OK按鈕')
                               
# 多加一個 Button 物件
my_button2 = tk.Button(my_window, text = '訊息框', command = show_message)
my_button2.pack()

# 進入事件迴圈
my_window.mainloop()

留言

張貼留言

這個網誌中的熱門文章

Python可以這樣玩(16):共陰/共陽七段顯示器

Python可以這樣玩(15):蜂鳴器與音樂

Python可以這樣玩(13):外部LED控制