Python結(jié)合PyQt5打造一個高級多功能計算器
?你有沒有遇到過這種場景——正在專心寫代碼或者處理報表,突然需要算點東西。打開系統(tǒng)自帶的計算器,發(fā)現(xiàn)它只是個“小學(xué)生水平”的工具,開個根號都要切到科學(xué)模式,更別提算三角函數(shù)或者做單位換算了。你嘆了口氣,要么打開網(wǎng)頁搜一個在線計算器,忍受一堆廣告的轟炸,要么干脆手算。
我當(dāng)時的想法很簡單:為什么不自己寫一個?
反正天天跟Python打交道,PyQt5這框架也聽說過不少次。與其讓別人的工具打斷工作流,不如親手打造一個趁手的“兵器”。這篇文章就是我折騰出來的成果——一個能當(dāng)主力工具用的多功能計算器,順便聊聊踩過的那些坑。
從界面開始,像搭積木一樣擺按鈕
寫GUI程序的第一步永遠是搭界面。PyQt5有個好處,可視化工具Qt Designer可以直接拖拖拽拽把框架搭好,不過我習(xí)慣手寫代碼——這樣以后改樣式、加功能心里更有數(shù)。
界面布局其實挺像擺積木。最上面放一個QLCDNumber作為顯示屏,要那種老式計算器的數(shù)字風(fēng)格,看著舒服。下面用QGridLayout把按鈕排成網(wǎng)格,四行四列不夠就加行,數(shù)字、運算符、功能鍵各就各位。
顏色我做了區(qū)分:數(shù)字按鈕白底藍字,運算符灰底黑字,AC(清空)用紅色,等號用綠色。這種視覺分組能讓操作更快,不用仔細看就知道哪個區(qū)域是干嘛的。
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import sys
import math
class Calculator(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("多功能計算器")
self.setFixedSize(400, 500)
# 顯示屏
self.display = QLCDNumber()
self.display.setDigitCount(15)
self.display.setSegmentStyle(QLCDNumber.Flat)
# 按鈕布局
self.create_buttons()
這里有個小技巧:顯示屏的digitCount設(shè)15位夠用了,真要算天文數(shù)字也不會用這個計算器。setSegmentStyle讓數(shù)字顯示更現(xiàn)代一點,老式凸起風(fēng)格有點過時。
按鈕動起來,信號與槽的靈魂所在
PyQt最核心的機制叫“信號與槽”,聽起來高大上,說白了就是“點一下按鈕,做一件事”。每個按鈕被點擊時發(fā)出clicked信號,我們把這個信號連接到對應(yīng)的處理函數(shù)上。
def create_buttons(self):
buttons = [
['7', '8', '9', '/'],
['4', '5', '6', '*'],
['1', '2', '3', '-'],
['0', '.', '=', '+'],
['C', '√', '^', 'AC']
]
grid = QGridLayout()
central_widget = QWidget()
central_widget.setLayout(grid)
self.setCentralWidget(central_widget)
# 把顯示屏和按鈕網(wǎng)格拼在一起
main_layout = QVBoxLayout()
main_layout.addWidget(self.display)
main_layout.addLayout(grid)
central_widget.setLayout(main_layout)
for row, row_buttons in enumerate(buttons):
for col, btn_text in enumerate(row_buttons):
btn = QPushButton(btn_text)
btn.clicked.connect(self.on_button_clicked)
grid.addWidget(btn, row, col)
上面代碼里的connect就是關(guān)鍵。不管按了哪個按鈕,都交給同一個on_button_clicked函數(shù)處理,通過按鈕上的文字來判斷要做什么。
計算邏輯,比想象中要麻煩一點
一開始我圖省事,直接用Python的eval函數(shù)計算表達式。這玩意兒確實方便,你給它字符串"2+3*4",它真能算出14。但eval有個大問題——不安全。惡意輸入可能執(zhí)行系統(tǒng)命令,雖然計算器場景風(fēng)險不高,但這習(xí)慣不好。
再說用戶體驗。eval計算時沒有實時反饋,你按完一連串?dāng)?shù)字和運算符,最后按等號才出結(jié)果。更好的做法是維護兩個狀態(tài):當(dāng)前輸入的數(shù)字和等待執(zhí)行的運算。
def on_button_clicked(self):
text = self.sender().text()
if text.isdigit() or text == '.':
# 數(shù)字或小數(shù)點,拼接到當(dāng)前輸入
self.current_input += text
self.display.display(self.current_input)
elif text in ['+', '-', '*', '/']:
# 運算符,保存當(dāng)前數(shù)字和運算符
self.last_number = float(self.current_input)
self.current_operator = text
self.current_input = ''
elif text == '=':
# 計算結(jié)果
current = float(self.current_input)
if self.current_operator == '+':
result = self.last_number + current
elif self.current_operator == '-':
result = self.last_number - current
# ... 其他運算
self.display.display(result)
self.current_input = str(result)
這種狀態(tài)機的方式讓計算器更“懂”你在做什么。按完“2+3”,顯示屏清空讓你輸?shù)诙€數(shù),最后按等號才出結(jié)果——這就是計算器該有的樣子。
進階功能,讓計算器真正“高級”起來
光有四則運算稱不上“高級”。科學(xué)計算器該有的東西得加上:三角函數(shù)、對數(shù)、開方、冪運算。
def calculate_function(self, func_name):
value = float(self.current_input)
if func_name == 'sqrt':
result = math.sqrt(value)
elif func_name == 'sin':
# 角度轉(zhuǎn)弧度
result = math.sin(math.radians(value))
elif func_name == 'cos':
result = math.cos(math.radians(value))
elif func_name == 'log':
result = math.log10(value)
elif func_name == 'ln':
result = math.log(value)
# ...
self.display.display(result)
self.current_input = str(result)
這里用Python標準庫的math模塊就夠了,不需要額外安裝東西。三角函數(shù)的坑是角度和弧度轉(zhuǎn)換,很多人第一次用math.sin(90)發(fā)現(xiàn)不是1,就是因為傳了角度進去,但函數(shù)要的是弧度。
還有個實用的功能是單位換算。長度、重量、溫度之間的轉(zhuǎn)換其實都是乘個系數(shù),用字典存起來就行。比如長度換算:{'m':1, 'cm':0.01, 'km':1000, 'inch':0.0254},用戶選“100 cm in m”這種格式,解析出來一乘一除就完事。
鍵盤支持,真正的效率提升
一個只能用鼠標點的計算器算不上趁手。加上鍵盤監(jiān)聽,讓數(shù)字小鍵盤也能操作。
def keyPressEvent(self, event):
key = event.key()
if key in [Qt.Key_0, Qt.Key_1, ..., Qt.Key_9]:
self.current_input += chr(key)
elif key == Qt.Key_Plus:
self.set_operator('+')
elif key == Qt.Key_Return or key == Qt.Key_Enter:
self.calculate_result()
elif key == Qt.Key_Backspace:
self.current_input = self.current_input[:-1]
elif key == Qt.Key_Escape:
self.clear_all()
self.display.display(self.current_input)
重寫keyPressEvent方法后,用戶甚至不需要碰鼠標。右手操作數(shù)字小鍵盤,左手輔助,這效率比系統(tǒng)計算器高太多了。
踩坑記錄,給后來人的避坑指南
Qt Designer確實能拖出界面,但生成的.ui文件要轉(zhuǎn)成.py,改一次轉(zhuǎn)一次,特別煩。不如手寫代碼,版本控制也方便。
布局管理器用QVBoxLayout和QGridLayout組合,別用絕對坐標place()。不同屏幕分辨率下,寫死的坐標會讓界面亂掉。布局管理器會自動適配,省心。
除法要處理除零錯誤,開方不能開負數(shù)。這些邊界條件不處理,程序一崩潰用戶體驗直接歸零。try-except包一下,彈個提示框就行。
try:
result = self.last_number / current
except ZeroDivisionError:
QMessageBox.warning(self, "錯誤", "除數(shù)不能為零")
return
為什么需要自己的計算器
市面上計算器那么多,為什么非要自己寫一個?因為沒有人比你更懂你的工作流。
你可能經(jīng)常需要把計算結(jié)果復(fù)制到某個特定格式里,或者要記錄每一次計算的歷史,又或者要用到某個冷門的物理常數(shù)。這些需求通用軟件不會幫你實現(xiàn),但自己的工具可以。代碼就在那里,想加什么功能隨時改。
寫完之后我把這個計算器設(shè)成了快捷鍵啟動,Ctrl+Alt+C呼出,算完自動把結(jié)果復(fù)制到剪貼板。這個功能實現(xiàn)起來也就十來行代碼,但每天都能省下幾十秒,一年算下來是個不小的數(shù)字。
好的工具不是買來的,是自己造的。當(dāng)你需要的時候,動手寫一個就是最好的選擇。
?到此這篇關(guān)于Python結(jié)合PyQt5打造一個高級多功能計算器的文章就介紹到這了,更多相關(guān)Python計算器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解Python list 與 NumPy.ndarry 切片之間的對比
這篇文章主要介紹了詳解Python list 與 NumPy.ndarry 切片之間的區(qū)別的相關(guān)資料,list 切片返回的是不原數(shù)據(jù),對新數(shù)據(jù)的修改不會影響原數(shù)據(jù)而NumPy.ndarry 的切片返回的是原數(shù)據(jù)需要的朋友可以參考下2017-07-07
Google colab中從kaggle中接入數(shù)據(jù)的操作方法
這篇文章主要介紹了Google colab中如何從kaggle中接入數(shù)據(jù),本文涉及到兩大平臺內(nèi)容,所以我默認你已經(jīng)擁有了,并且使用過了一段時間的google賬號和kaggle賬號,需要的朋友可以參考下2024-03-03
python神經(jīng)網(wǎng)絡(luò)編程實現(xiàn)手寫數(shù)字識別
這篇文章主要為大家詳細介紹了python神經(jīng)網(wǎng)絡(luò)編程實現(xiàn)手寫數(shù)字識別,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-05-05
python GUI庫圖形界面開發(fā)之PyQt5 MDI(多文檔窗口)QMidArea詳細使用方法與實例
這篇文章主要介紹了python GUI庫圖形界面開發(fā)之PyQt5 MDI(多文檔窗口)QMidArea詳細使用方法與實例,需要的朋友可以參考下2020-03-03

