Python tkinter計算器
Python版本:3.7
By : zeis
最近在學Python,一開始是看Python教程 - 廖雪峰的官方網站,但是看到“面對物件高階程式設計”那邊就沒耐心看了,不過網站還是很不錯的。後來把《簡明Python教程》(原著叫《A Byte of Python》)看完了,這個教程我感覺還是很不錯,適合我這樣沒耐心的人看。
又瞭解了圖形介面後,就想著做個簡單的計算器,為此找了好多資料,可能是我太笨了吧,emmmmm…
現在計算器算是完成一部分了,所以我就打算寫個筆記記錄一下,也是為了讓其他跟我一樣的人不用再去找好多資料,只看我這個就可以。
tkinter
tkinter是Python自帶的標準GUI(圖形使用者介面)包,使用它不需要再安裝其他的東西,直接使用即可。
程式部分
1
from tkinter import *
from tkinter import messagebox
import operator
程式的第一部分當然是import啦,第一行是匯入tkinter包的“所有”內容,第二行是匯入tkinter 包的messagebox模組,messagebox模組是用來做彈窗的,第三行operator包在本次程式中是用來實現對比兩個列表是否相等,其他功能這裡不講。
要注意的是其實第一行這樣匯入並不會真正匯入tkinter 包的所有內容,messagebox就是沒有匯入的部分之一,所以還需要第二行。
這是我找到的解釋:
包匯入的過程和模組的基本一致,只是匯入包的時候會執行此包目錄下的__init__.py,而不是模組裡面的語句了。另外,如果只是單純的匯入包,而包的__init__.py中又沒有明確的其他初始化操作,那麼此包下面的模組是不會自動匯入的。
2
lists = [] #設定一個變數 儲存運算數字和符號的列表
class Application(Frame):
def __init__(self,master = None):
Frame.__init__(self, master)
self.master.geometry('320x450')
self.master.resizable(0, 0) # 阻止Python GUI的大小調整
self.createWidgets()
首先這裡定義了一個列表lists ,用來儲存輸入內容。
在GUI中,每個Button、Label、輸入框等,都是一個Widget(控制元件)。在tkinter中用Frame表示視窗,Frame也是一個Widget,Frame可以容納其它Widget。本程式中從Frame類派生出Application類,來容納各種Widget。
Application類的建構函式 __init__(self,master=None)
self
代表Application
本身,(在tkinter中,一個Widget可能屬於另一個Widget,這時的另一個Widget就是這個控制元件的master
)而視窗沒有master
,所以在這裡master=None
。geometry('320x450')
表示將視窗大小設為“320*450”大小,self.createWidgets()
是建立Widgets的方法,具體在後面。resizable(0, 0)
表示不允許調節視窗大小,將引數設為1則表示允許調節。
3
def createWidgets(self):
#增加選單
self.menuBar = Menu(self.master) #建立選單的例項
self.master.config(menu = self.menuBar) #將根視窗的頂級選單設定為menu
#設定選單選項
#建立一個下拉選單‘關於’,這個選單是掛在menubar(頂級選單)上的
#tearoff的值有0和1,為0時表示子選單不獨立出來。
aboutMenu=Menu(self.menuBar,tearoff=0)
#建立一個下拉選單‘功能’,這個選單是掛在menubar(頂級選單)上的
moreMenu=Menu(self.menuBar,tearoff=0)
#用add_cascade()將選單新增到頂級選單中,按新增順序排列
self.menuBar.add_cascade(label='功能',menu=moreMenu)
self.menuBar.add_cascade(label='幫助',menu=aboutMenu)
#下拉選單的具體專案,使用add_command()方法
aboutMenu.add_command(label='關於',command=self.About)
moreMenu.add_command(label='其他',command=self.Other)
# 顯示面板
self.result = StringVar()
self.result.set(0) # 顯示面板顯示結果1,用於顯示預設數字0
self.result2 = StringVar() # 顯示面板顯示結果2,用於顯示計算過程
self.result2.set('')
# 顯示面板設定
self.label = Label(self.master, font=('微軟雅黑', 20), bg='#FFFFFF', bd='0', fg='#828282', anchor='se',\
textvariable=self.result2)
self.label.place(width=320, height=130)
self.label2 = Label(self.master, font=('微軟雅黑', 25), bg='#FFFFFF', bd='0', fg='black', anchor='se',\
textvariable=self.result)
self.label2.place(y=130, width=320, height=70)
######################數字鍵###########################
self.Button1 = Button(self.master, text='7', font=('微軟雅黑', 20), fg=('#4F4F4F'), bg=('#FFFFF0'), bd=0,\
command=lambda: self.pressNum('7'))
self.Button1.place(x=0, y=250, width=80, height=50)
self.Button2 = Button(self.master, text='8', font=('微軟雅黑', 20), fg=('#4F4F4F'), bg=('#FFFFF0'), bd=0, \
command=lambda: self.pressNum('8'))
self.Button2.place(x=80, y=250, width=80, height=50)
self.Button3 = Button(self.master, text='9', font=('微軟雅黑', 20), fg=('#4F4F4F'), bg=('#FFFFF0'), bd=0, \
command=lambda: self.pressNum('9'))
self.Button3.place(x=160, y=250, width=80, height=50)
self.Button4 = Button(self.master, text='4', font=('微軟雅黑', 20), fg=('#4F4F4F'), bg=('#FFFFF0'), bd=0.1, \
command=lambda: self.pressNum('4'))
self.Button4.place(x=0, y=300, width=80, height=50)
self.Button5 = Button(self.master, text='5', font=('微軟雅黑', 20), fg=('#4F4F4F'), bg=('#FFFFF0'), bd=0.1, \
command=lambda: self.pressNum('5'))
self.Button5.place(x=80, y=300, width=80, height=50)
self.Button6 = Button(self.master, text='6', font=('微軟雅黑', 20), fg=('#4F4F4F'), bg=('#FFFFF0'), bd=0.1, \
command=lambda: self.pressNum('6'))
self.Button6.place(x=160, y=300, width=80, height=50)
self.Button7 = Button(self.master, text='1', font=('微軟雅黑', 20), fg=('#4F4F4F'), bg=('#FFFFF0'), bd=0.1, \
command=lambda: self.pressNum('1'))
self.Button7.place(x=0, y=350, width=80, height=50)
self.Button8 = Button(self.master, text='2', font=('微軟雅黑', 20), fg=('#4F4F4F'), bg=('#FFFFF0'), bd=0.1, \
command=lambda: self.pressNum('2'))
self.Button8.place(x=80, y=350, width=80, height=50)
self.Button9 = Button(self.master, text='3', font=('微軟雅黑', 20), fg=('#4F4F4F'), bg=('#FFFFF0'), bd=0.1, \
command=lambda: self.pressNum('3'))
self.Button9.place(x=160, y=350, width=80, height=50)
self.Button10 = Button(self.master, text='.', font=('微軟雅黑', 20), fg=('#4F4F4F'), bg=('#FFFFF0'), bd=0.1, \
command=lambda: self.pressNum('.'))
self.Button10.place(x=0, y=400, width=80, height=50)
self.Button11 = Button(self.master, text='0', font=('微軟雅黑', 20), fg=('#4F4F4F'), bg=('#FFFFF0'), bd=0.1, \
command=lambda: self.pressNum('0'))
self.Button11.place(x=80, y=400, width=80, height=50)
######################運算鍵###########################
self.Button12 = Button(self.master, text='=', font=('微軟雅黑', 20), fg=('#4F4F4F'), bg=('#EED8AE'), bd=0.1, \
command=lambda: self.pressEqual())
self.Button12.place(x=160, y=400, width=80, height=50)
self.Button13 = Button(self.master, text='+', font=('微軟雅黑', 20), fg=('#4F4F4F'), bg=('#F5FFFA'), bd=0.1, \
command=lambda: self.pressOperator('+'))
self.Button13.place(x=240, y=250, width=80, height=50)
self.Button14 = Button(self.master, text='-', font=('微軟雅黑', 20), fg=('#4F4F4F'), bg=('#F5FFFA'), bd=0.1, \
command=lambda: self.pressOperator('-'))
self.Button14.place(x=240, y=300, width=80, height=50)
self.Button15 = Button(self.master, text='*', font=('微軟雅黑', 20), fg=('#4F4F4F'), bg=('#F5FFFA'), bd=0.1, \
command=lambda: self.pressOperator('*'))
self.Button15.place(x=240, y=350, width=80, height=50)
self.Button16 = Button(self.master, text='/', font=('微軟雅黑', 20), fg=('#4F4F4F'), bg=('#F5FFFA'), bd=0.1, \
command=lambda: self.pressOperator('/'))
self.Button16.place(x=240, y=400, width=80, height=50)
######################特殊鍵###########################
self.Button17 = Button(self.master, text='清零', font=('微軟雅黑', 15), fg=('#4F4F4F'),bg=('#FFEC8B'), bd=0.1, \
command=lambda: self.Clr())
self.Button17.place(x=0, y=200, width=80, height=50)
self.Button18 = Button(self.master, text='^2', font=('微軟雅黑', 20), fg=('#4F4F4F'), bg=('#F5FFFA'), bd=0.1, \
command=lambda: self.Square())
self.Button18.place(x=80, y=200, width=80, height=50)
self.Button19 = Button(self.master, text='sqrt', font=('微軟雅黑', 20), fg=('#4F4F4F'), bg=('#F5FFFA'), bd=0.1, \
command=lambda: self.Sqrt())
self.Button19.place(x=160, y=200, width=80, height=50)
self.Button20 = Button(self.master, text='刪除', font=('微軟雅黑', 15), fg=('#4F4F4F'), bg=('#FFEC8B'), bd=0.1, \
command=lambda: self.BackSp())
self.Button20.place(x=240, y=200, width=80, height=50)
createWidgets(self)
方法可以分為三個部分:
-
選單:
由於內容比較少,具體看程式註釋。
tearoff = 0:
tearoff = 1:
-
顯示面板:
StringVar()
是Tk庫內部定義的字串變數型別,可以用它來顯示計算內容,set()
用來改變值,get()
用來獲取值。
在 Tkinter 中,Label 控制元件用以顯示文字和圖片。本程式用了兩個Label分別來顯示計算過程和計算結果,本次用到的引數有:
引數 | 解釋 |
---|---|
font | 設定字型跟文字大小 |
bg | 設定背景顏色 |
bd | 指定Label的邊框寬度 |
fg | 設定Label的文字和點陣圖的顏色 |
anchor | 控制文字(或影象)在Label中顯示位置 n,ne,e,se,s,sw,w,nw,或center來定位(ewsn代表東西南北,上北下南左西右東) |
textvariable | Label顯示Tkinter變數(通常是一個StringVar變數)的內容 |
最後用place()
來設定位置和大小。
- 按鈕
使用Button()建立各個按鍵,其引數:
引數 | 解釋 |
---|---|
text | 指定按鈕上顯示的文字 |
font | 按鈕上文字的字型和大小 |
fg | 按鈕的前景色,即文字顏色 |
bg | 按鈕的背景色 |
bd | 按鈕的邊框寬度 |
command | 按鈕訊息的回撥函式 |
由於tkinter要求由按鈕(或者其它的外掛)觸發的控制器函式不能含有引數,目的就是為了以統一的方式去呼叫他們。我們可以使用lambda來給函式傳遞引數。
lambda可以使在任何地方建立一個沒有名字的單行函式,即匿名函式。我的理解是在
Button(self.master, text='7', font=('微軟雅黑', 20), fg=('#4F4F4F'), bg=('#FFFFF0'), bd=0,command=lambda: self.pressNum('7'))
中lambda: self.pressNum('7')
是一個匿名函式,而不是單純呼叫self.pressNum()
,但最後得到的效果就是呼叫self.pressNum()
的效果是一樣的。只不過如果command=self.pressNum('7')
這樣的形式的話,那麼在建立按鍵時就會直接執行self.pressNum('7')
,程式就會出問題。
4
#數字鍵處理函式,屬於Application()類
def pressNum(self,val):
global lists
lists.append(val)
#使用join()將列表轉換成字串,再顯示到Label中
app.result_set(''.join(lists))
當按下數字鍵時呼叫的函式,每按下一次則會向全域性列表lists
新增一個元素,然後顯示出來。
#運算子號鍵處理函式,屬於Application()類
def pressOperator(self,val):
global lists
if len(lists) > 0:
if lists[-1] in ['+','-','*','/']:
lists[-1] = val
else:
lists.append(val)
app.result_set(''.join(lists))
相比數字鍵處理函式多了一個判斷當前已輸入內容最後一位是否為運算子號,如果是替換它,否則新增該元素。
#等號鍵處理函式
def pressEqual(self):
global lists
if len(lists) > 0:
if operator.eq(lists,['1','+']):
lists.clear()
app.result2_set('')
app.result_set('Python')
else:
if lists[-1] in ['+','-','*','/']