跳到內容

GUI 計算機

延續上一個 tkinter 專題,這次做一台計算機:一格一格的數字和運算符號按鈕,按了顯示在螢幕上,按「=」算出結果,另外還有清除和退格。這個專題會用到 tkinter 的格線排版、巢狀迴圈搭配 enumerate(),以及上一頁的 functools.partial。

把它存成 gui_calc.py 執行:

import functools
import tkinter as tk
def button_clicked(button_text):
if button_text == "C":
entry.delete(0, tk.END)
return
current_text = entry.get()
if button_text == "<-":
entry.delete(len(current_text) - 1, tk.END)
return
if button_text == "=":
entry.delete(0, tk.END)
try:
result = eval(current_text)
except Exception:
entry.insert(tk.END, "計算錯誤")
else:
entry.insert(tk.END, result)
return
entry.insert(tk.END, button_text)
font = ("Arial", 16)
window = tk.Tk()
window.title("GUI 計算機")
entry = tk.Entry(window, width=20, font=font)
entry.grid(row=0, column=0, columnspan=4)
button_grid = [
["7", "8", "9", "/"],
["4", "5", "6", "*"],
["1", "2", "3", "-"],
["0", ".", "=", "+"],
["C", "<-"],
]
for row, button_row in enumerate(button_grid, 1):
for col, button_text in enumerate(button_row):
button = tk.Button(
window,
text=button_text,
width=5,
height=2,
font=font,
command=functools.partial(button_clicked, button_text),
)
button.grid(row=row, column=col)
window.mainloop()

這次用 grid(row=, column=) 而不是 pack。它把視窗切成一格一格,你指定每個元件放在第幾列、第幾欄,很適合排計算機這種格子狀的版面。

  • entry.grid(row=0, column=0, columnspan=4):螢幕放在第 0 列,columnspan=4 讓它橫跨四欄。
  • button_grid 是一個二維串列,直接照計算機的樣子把每一列的按鈕文字排好。最後一列只有兩顆,grid 不會介意。
  • 外層 for row, button_row in enumerate(button_grid, 1) 走過每一列,enumerate 從 1 開始數,因為第 0 列給螢幕用了。內層 for col, button_text in enumerate(button_row) 走過這一列的每顆按鈕,欄從 0 開始。
  • 每顆按鈕都用 functools.partial(button_clicked, button_text) 綁上自己的文字,道理和上一頁一樣:command 要的是不帶引數的函式,partial 幫我們把 button_text 先塞進去。

font = ("Arial", 16) 把字型設定放在一個變數,螢幕和每顆按鈕共用,要改字型或大小只要改一個地方。

所有按鈕都呼叫同一個函式 button_clicked,靠 button_text 分辨是哪一顆。函式用一連串的提早 return 先處理三顆特殊按鈕,最後才是一般的數字和符號:

  • C(清除):entry.delete(0, tk.END) 把螢幕從第 0 個字元刪到最後,也就是全部清空,然後 return。
  • <-(退格):先用 entry.get() 拿到目前的字串,entry.delete(len(current_text) - 1, tk.END) 從最後一個字元的位置刪到結尾,剛好刪掉一個字,然後 return。
  • =(計算):先把螢幕清空,再用 eval(current_text) 把螢幕上的算式字串(例如 "3+4*2")當成 Python 運算式算出答案。這裡用了錯誤處理那章的 try / except / else:算式打錯(例如 3++)會出錯,except 接住後在螢幕顯示「計算錯誤」;沒出錯才走 else,把結果填回螢幕。兩條路最後都 return。
  • 其他按鈕:數字和運算符號都一樣,entry.insert(tk.END, button_text) 把它接在螢幕文字的最後面。

注意 current_text = entry.get() 放在第一個 return 之後、<- 和 = 的判斷之前:C 用不到目前的文字,所以不必先拿;後面兩顆都要用,就在它們前面拿一次。

eval 很方便,但也要小心。它會執行字串裡的任何 Python 程式,只適合像這樣自己掌控輸入的小練習,別拿它去算來路不明的字串。這台計算機的輸入只能來自按鈕,所以是安全的。

v0.9.1 (c924b5b)