簡單計算機
這篇教學會透過 PyQt5 的 QPushButton、QLabel 組合成一個簡單的計算機,實作過程中會利用字典 ( dict ) 定義按鈕群組,搭配邏輯判斷進行點擊後數值的加減乘除運算。
快速導覽:
- PyQt6 版本參考:PyQt6 教學 - 簡單計算機
- 因為 Google Colab 不支援 PyQt5,所以請使用本機環境 ( 參考:使用 Python 虛擬環境 ) 或使用 Anaconda Jupyter 進行實作 ( 參考:使用 Anaconda )。
計算機畫面設計
參考QLabel 標籤」教學範例,在畫面中加入 QLabel 顯示計算機數字和公式,接著參考「QPushButton 按鈕」教學範例,先建立一個字典型態的變數定義按鈕的文字 ( 鍵 ) 和座標位置 ( 值 ),並將座標要改變的幅度和寬高尺寸獨立成變數方便後續計算,定義完成後就能透過 for 迴圈,根據字典內容一次建立完成所有的按鈕。
- 參考:字典 dictionary、for 迴圈
- 注意 lambda 匿名函式裡需要額外加上 checked 參數。
from PyQt5 import QtWidgets
from PyQt5.QtCore import *
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
MainWindow.setObjectName("MainWindow")
MainWindow.setWindowTitle("oxxo.studio")
MainWindow.resize(300, 280)
label = QtWidgets.QLabel(MainWindow) # 建立 QLabel
label.setGeometry(30, 10, 240, 40) # 定義位置
# 定義樣式
label.setStyleSheet('''
background:#ffffff;
border:1px solid #000;
font-size:20px;
padding:5px;
''')
label.setAlignment(Qt.AlignRight) # 靠右對齊
label.setText('0')
# 定義按鈕群組中需要共用的變數
x = 30
y = 60
w = 60
h = 50
# 定義按鈕群組
btns = {
'7':{'x':x,'y':y},
'8':{'x':x+w,'y':y},
'9':{'x':x+2*w,'y':y},
'+':{'x':x+3*w,'y':y},
'4':{'x':x,'y':y+h},
'5':{'x':x+w,'y':y+h},
'6':{'x':x+2*w,'y':y+h},
'-':{'x':x+3*w,'y':y+h},
'1':{'x':x,'y':y+2*h},
'2':{'x':x+w,'y':y+2*h},
'3':{'x':x+2*w,'y':y+2*h},
'*':{'x':x+3*w,'y':y+2*h},
'AC':{'x':x,'y':y+3*h},
'0':{'x':x+w,'y':y+3*h},
'=':{'x':x+2*w,'y':y+3*h},
'/':{'x':x+3*w,'y':y+3*h},
}
# 依序取出按鈕群組中的每個項目
for i in btns:
btns[i]['qw'] = QtWidgets.QPushButton(MainWindow) # 建立 QPuahButton
# 定義樣式
btns[i]['qw'].setStyleSheet('''
QPushButton{
font-size:16px;
border-radius:5px;
border:1px solid #000;
background:#ccc;
margin:3px;
}
QPushButton:pressed{
background:#aaa;
}
''')
btns[i]['qw'].setText(i) # 設定文字
btns[i]['qw'].setGeometry(btns[i]['x'], btns[i]['y'], w, h) # 設定位置和尺寸
btns[i]['qw'].clicked.connect(lambda checked, n=i: showNum(n)) # 設定點擊按鈕時執行 showNum 函式
MainWindow.show()
sys.exit(app.exec_())
計算機功能設計
畫面設計完成後,接著編輯 showNum 函式內容:
# 顯示數字函式,n 為點擊按鈕時要帶入的數值
def showNum(n):
global num
if n == 'AC':
num = '0' # 如果按下數字,數值歸零
elif n == '=':
try:
num = str(eval(num)) # 如果按下等號,使用 eval() 計算結果
except:
num = 'error' # 如果計算結果發生錯誤,回傳 error
else:
if num == '0' and n in '0123456789':
num = n # 如果數值原本是 0,且按下數字鍵,就讓數字變成所按下的數字
else:
num = num + n # 否則就用字串的方式累加
label.setText(num) # QLabel 顯示結果
if num == 'error':
num = '0' # 如果發生錯誤,數值歸零
完整程式碼
一般寫法:
from PyQt5 import QtWidgets
from PyQt5.QtCore import *
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
MainWindow.setObjectName("MainWindow")
MainWindow.setWindowTitle("oxxo.studio")
MainWindow.resize(300, 280)
label = QtWidgets.QLabel(MainWindow)
label.setGeometry(30, 10, 240, 40)
label.setStyleSheet('''
background:#ffffff;
border:1px solid #000;
font-size:20px;
padding:5px;
''')
label.setAlignment(Qt.AlignRight)
label.setText('0')
num = '0'
def showNum(n):
global num
if n == 'AC':
num = '0'
elif n == '=':
try:
num = str(eval(num))
except:
num = 'error'
else:
if num == '0' and n in '0123456789':
num = n
else:
num = num + n
label.setText(num)
if num == 'error':
num = '0'
x = 30
y = 60
w = 60
h = 50
btns = {
'7':{'x':x,'y':y},
'8':{'x':x+w,'y':y},
'9':{'x':x+2*w,'y':y},
'+':{'x':x+3*w,'y':y},
'4':{'x':x,'y':y+h},
'5':{'x':x+w,'y':y+h},
'6':{'x':x+2*w,'y':y+h},
'-':{'x':x+3*w,'y':y+h},
'1':{'x':x,'y':y+2*h},
'2':{'x':x+w,'y':y+2*h},
'3':{'x':x+2*w,'y':y+2*h},
'*':{'x':x+3*w,'y':y+2*h},
'AC':{'x':x,'y':y+3*h},
'0':{'x':x+w,'y':y+3*h},
'=':{'x':x+2*w,'y':y+3*h},
'/':{'x':x+3*w,'y':y+3*h},
}
for i in btns:
btns[i]['qw'] = QtWidgets.QPushButton(MainWindow)
btns[i]['qw'].setStyleSheet('''
QPushButton{
font-size:16px;
border-radius:5px;
border:1px solid #000;
background:#ccc;
margin:3px;
}
QPushButton:pressed{
background:#aaa;
}
''')
btns[i]['qw'].setText(i)
btns[i]['qw'].setGeometry(btns[i]['x'], btns[i]['y'], w, h)
btns[i]['qw'].clicked.connect(lambda checked, n=i: showNum(n))
MainWindow.show()
sys.exit(app.exec_())
使用 class 寫法:
from PyQt5 import QtWidgets
from PyQt5.QtCore import *
import sys
class MyWidget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle('oxxo.studio')
self.resize(300, 280)
self.ui()
def ui(self):
self.label = QtWidgets.QLabel(self)
self.label.setGeometry(30, 10, 240, 40)
self.label.setStyleSheet('''
background:#ffffff;
border:1px solid #000;
font-size:20px;
padding:5px;
''')
self.label.setAlignment(Qt.AlignRight)
self.label.setText('0')
self.num = '0'
x = 30
y = 60
w = 60
h = 50
self.btns = {
'7':{'x':x,'y':y},
'8':{'x':x+w,'y':y},
'9':{'x':x+2*w,'y':y},
'+':{'x':x+3*w,'y':y},
'4':{'x':x,'y':y+h},
'5':{'x':x+w,'y':y+h},
'6':{'x':x+2*w,'y':y+h},
'-':{'x':x+3*w,'y':y+h},
'1':{'x':x,'y':y+2*h},
'2':{'x':x+w,'y':y+2*h},
'3':{'x':x+2*w,'y':y+2*h},
'*':{'x':x+3*w,'y':y+2*h},
'AC':{'x':x,'y':y+3*h},
'0':{'x':x+w,'y':y+3*h},
'=':{'x':x+2*w,'y':y+3*h},
'/':{'x':x+3*w,'y':y+3*h},
}
for i in self.btns:
self.btns[i]['qw'] = QtWidgets.QPushButton(self)
self.btns[i]['qw'].setStyleSheet('''
QPushButton{
font-size:16px;
border-radius:5px;
border:1px solid #000;
background:#ccc;
margin:3px;
}
QPushButton:pressed{
background:#aaa;
}
''')
self.btns[i]['qw'].setText(i)
self.btns[i]['qw'].setGeometry(self.btns[i]['x'], self.btns[i]['y'], w, h)
self.btns[i]['qw'].clicked.connect(lambda checked, n=i: self.showNum(n))
def showNum(self, n):
if n == 'AC':
self.num = '0'
elif n == '=':
try:
self.num = str(eval(self.num))
except:
self.num = 'error'
else:
if self.num == '0' and n in '0123456789':
self.num = n
else:
self.num = self.num + n
self.label.setText(self.num)
if self.num == 'error':
self.num = '0'
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
Form = MyWidget()
Form.show()
sys.exit(app.exec_())
意見回饋
如果有任何建議或問題,可傳送「意見表單」給我,謝謝~