【原创】Python与PyQt5结合:一步步创建功能强大的科学计算器 实战有效 python开发跨平台小工具
本科学计算器,实现多种数学函数和常量的支持,界面用 PyQt5 构建。python3.11 实现,功能如下:
1,基本运算:加、减、乘、除。
2,进阶运算:幂、平方根、立方根、倒数等。
3,三角函数:正弦、余弦、正切、反正弦、反余弦、反正切。
4,对数和指数函数:自然对数、常用对数、以任何基数的对数、指数函数。
5,常量:π (圆周率)、e (自然对数的底)。
6,其他功能:清空当前输入、删除最后一个字符、显示历史记录等。模仿win10自带的科学计算机风格界面.
7,键盘输入功能
实现思路
-
环境配置:
- 确保已安装 Python 3.11 和 PyQt5。
- 安装 math 模块(标准库,通常已包含)。
-
界面设计:
- 使用 PyQt5 设计图形用户界面 (GUI)。
- 模仿 Windows 10 科学计算器的布局和风格。
- 使用
QMainWindow
作为主窗口,QWidget
和QGridLayout
进行布局。
-
功能实现:
- 基本运算:加、减、乘、除。
- 进阶运算:幂、平方根、立方根、倒数。
- 三角函数:正弦、余弦、正切及其反函数。
- 对数和指数函数:自然对数、常用对数、任意底数对数、指数函数。
- 常量:π 和 e。
- 其他功能:清空当前输入、删除最后一个字符、显示历史记录。
-
数学运算处理:
- 使用
math
模块提供的函数进行数学计算。 - 处理运算符优先级和表达式计算,可使用
eval()
函数但需确保安全性。
- 使用
-
历史记录管理:
- 使用列表存储历史记录。
- 提供查看历史记录的功能,可以是菜单选项或单独窗口。
-
用户交互:
- 按钮点击事件处理。
- 输入验证和错误处理,确保用户输入合法。
- 单位切换(角度/弧度)功能。
-
实现键盘输入功能:
- 我们需要在
ScientificCalculator
类中重写keyPressEvent
方法,并确保窗口能够捕获键盘事件。以下是完整的实现步骤和代码:
- 我们需要在
代码解释
-
环境配置:
- 导入所需的模块和库。
- 确保 Python 版本为 3.11,使用 PyQt5 构建 GUI。
-
界面设计:
- 使用
QMainWindow
作为主窗口,设置窗口标题和固定大小。 QLineEdit
用于显示输入和结果,设置为只读,右对齐。- 使用
QGridLayout
布局按钮,定义按钮文本和位置。
- 使用
-
功能实现:
- 基本运算:通过按钮点击事件,将操作符添加到
current_input
中,最终使用eval()
计算结果。 - 进阶运算:使用
math
模块的函数进行计算,结果添加到显示区域。 - 三角函数:处理角度和弧度的转换,结果根据模式计算。
- 对数和指数函数:使用
math
模块对应的函数进行计算。 - 常量:π 和 e 直接从
math
模块获取,添加到输入中。 - 其他功能:
C
按钮清空输入。Del
按钮删除最后一个字符。History
按钮显示历史记录窗口。
- 基本运算:通过按钮点击事件,将操作符添加到
-
历史记录管理:
- 使用列表
history
存储历史记录。 update_history_menu
方法更新菜单中的历史记录选项。show_history
方法显示历史记录窗口。
- 使用列表
-
用户交互:
- 按钮点击事件通过
on_button_click
方法处理。 - 使用
QMessageBox
显示错误信息。 - 提供角度和弧度切换功能(未在代码中实现,可自行添加)。
- 按钮点击事件通过
注意事项
-
安全性:
- 使用
eval()
函数存在安全风险,建议使用安全的表达式解析库,如asteval
。
- 使用
-
输入验证:
- 需要添加更多的输入验证,确保用户输入合法,避免计算错误。
-
用户体验:
- 可以添加更多的功能和改进界面美观度,如主题切换、更大的显示屏等。
-
代码优化:
- 可以将按钮和功能映射到字典中,减少代码重复。
- 将历史记录保存到文件中,方便持久化存储。
实现步骤
-
设置焦点策略:
- 在
__init__
方法中设置self.setFocusPolicy(Qt.StrongFocus)
,以确保窗口能够捕获键盘事件。
- 在
-
重写
keyPressEvent
方法:- 创建一个字典
key_map
,将按键与其对应的字符映射起 - 来。
- 根据按下的键,将相应的字符添加到
current_input
中,并更新显示区域。 - 处理特殊键,如回车键(执行计算)、退格键(删除最后一个字符)、Escape键(清空输入)。
- 创建一个字典
-
确保事件处理方法被调用:
- 确保
keyPressEvent
方法正确重写,并且逻辑无误。
- 确保
代码实现
import sys
import math
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QGridLayout, QPushButton, QLineEdit, QVBoxLayout, QMessageBox, QAction, QMenu
from PyQt5.QtCore import Qt
class ScientificCalculator(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Scientific Calculator")
self.setFixedSize(400, 500)
self.display = QLineEdit()
self.display.setReadOnly(True)
self.display.setAlignment(Qt.AlignRight)
self.display.setMaxLength(25)
self.history = []
self.current_input = ""
self.is_degree = True # Default to degree mode
main_layout = QVBoxLayout()
main_layout.addWidget(self.display)
button_layout = QGridLayout()
# Define buttons
buttons = [
['sin', 'cos', 'tan', 'π'],
['asin', 'acos', 'atan', 'e'],
['x^2', 'x^3', 'sqrt', '1/x'],
['log', 'ln', 'log₂', 'exp'],
['7', '8', '9', '/'],
['4', '5', '6', '*'],
['1', '2', '3', '-'],
['0', '.', '±', '+'],
['C', 'Del', 'History', '='],
]
row = 0
for button_row in buttons:
col = 0
for btn_text in button_row:
btn = QPushButton(btn_text)
btn.setFixedSize(80, 80)
button_layout.addWidget(btn, row, col)
col += 1
btn.clicked.connect(self.on_button_click)
row += 1
main_layout.addLayout(button_layout)
container = QWidget()
container.setLayout(main_layout)
self.setCentralWidget(container)
# Create a menu for history
self.history_menu = QMenu("History", self)
self.menuBar().addMenu(self.history_menu)
# Set focus policy to capture key events
self.setFocusPolicy(Qt.StrongFocus)
def keyPressEvent(self, event):
key = event.key()
key_map = {
Qt.Key_0: '0',
Qt.Key_1: '1',
Qt.Key_2: '2',
Qt.Key_3: '3',
Qt.Key_4: '4',
Qt.Key_5: '5',
Qt.Key_6: '6',
Qt.Key_7: '7',
Qt.Key_8: '8',
Qt.Key_9: '9',
Qt.Key_Period: '.',
Qt.Key_Plus: '+',
Qt.Key_Minus: '-',
Qt.Key_Asterisk: '*',
Qt.Key_Slash: '/',
# 其他运算符可以后续添加
}
if key in key_map:
if key_map[key] == '.' and '.' in self.current_input:
# 已经有小数点了,不添加
pass
else:
self.current_input += key_map[key]
self.display.setText(self.current_input)
elif key == Qt.Key_Return or key == Qt.Key_Enter:
self.on_button_click('=')
elif key == Qt.Key_Backspace:
self.on_button_click('Del')
elif key == Qt.Key_Escape:
self.on_button_click('C')
else:
# 忽略其他键
pass
def on_button_click(self, text=None):
if text is None:
sender = self.sender()
text = sender.text()
if text == "C":
self.current_input = ""
self.display.clear()
elif text == "Del":
self.current_input = self.current_input[:-1]
self.display.setText(self.current_input)
elif text == "=":
try:
result = str(eval(self.current_input))
self.history.append(f"{self.current_input} = {result}")
self.update_history_menu()
self.display.setText(result)
self.current_input = result
except:
QMessageBox.warning(self, "Error", "Invalid expression")
self.current_input = ""
self.display.clear()
# 其他按钮处理逻辑...
def update_history_menu(self):
self.history_menu.clear()
for entry in self.history:
action = QAction(entry, self)
self.history_menu.addAction(action)
if __name__ == "__main__":
app = QApplication(sys.argv)
calculator = ScientificCalculator()
calculator.show()
sys.exit(app.exec_())
代码解释
-
设置焦点策略:
self.setFocusPolicy(Qt.StrongFocus)
确保窗口能够捕获键盘事件。
-
重写
keyPressEvent
方法:- 使用字典
key_map
将按键与其对应的字符映射起来。 - 根据按下的键,将相应的字符添加到
current_input
中,并更新显示区域。 - 处理特殊键,如回车键(执行计算)、退格键(删除最后一个字符)、Escape键(清空输入)。
- 使用字典
-
确保事件处理方法被调用:
keyPressEvent
方法被正确重写,并且逻辑无误。
代码学习,前言技术分享,深度分析编程技术,普及科普编程技术,天天都要敲代码
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)