【原创】Python与PyQt5结合:一步步创建功能强大的科学计算器 实战有效 python开发跨平台小工具

在这里插入图片描述
在这里插入图片描述

本科学计算器,实现多种数学函数和常量的支持,界面用 PyQt5 构建。python3.11 实现,功能如下:
1,基本运算:加、减、乘、除。
2,进阶运算:幂、平方根、立方根、倒数等。
3,三角函数:正弦、余弦、正切、反正弦、反余弦、反正切。
4,对数和指数函数:自然对数、常用对数、以任何基数的对数、指数函数。
5,常量:π (圆周率)、e (自然对数的底)。
6,其他功能:清空当前输入、删除最后一个字符、显示历史记录等。模仿win10自带的科学计算机风格界面.
7,键盘输入功能

实现思路

  1. 环境配置

    • 确保已安装 Python 3.11 和 PyQt5。
    • 安装 math 模块(标准库,通常已包含)。
  2. 界面设计

    • 使用 PyQt5 设计图形用户界面 (GUI)。
    • 模仿 Windows 10 科学计算器的布局和风格。
    • 使用 QMainWindow 作为主窗口,QWidgetQGridLayout 进行布局。
  3. 功能实现

    • 基本运算:加、减、乘、除。
    • 进阶运算:幂、平方根、立方根、倒数。
    • 三角函数:正弦、余弦、正切及其反函数。
    • 对数和指数函数:自然对数、常用对数、任意底数对数、指数函数。
    • 常量:π 和 e。
    • 其他功能:清空当前输入、删除最后一个字符、显示历史记录。
  4. 数学运算处理

    • 使用 math 模块提供的函数进行数学计算。
    • 处理运算符优先级和表达式计算,可使用 eval() 函数但需确保安全性。
  5. 历史记录管理

    • 使用列表存储历史记录。
    • 提供查看历史记录的功能,可以是菜单选项或单独窗口。
  6. 用户交互

    • 按钮点击事件处理。
    • 输入验证和错误处理,确保用户输入合法。
    • 单位切换(角度/弧度)功能。
  7. 实现键盘输入功能

    • 我们需要在 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
  • 输入验证

    • 需要添加更多的输入验证,确保用户输入合法,避免计算错误。
  • 用户体验

    • 可以添加更多的功能和改进界面美观度,如主题切换、更大的显示屏等。
  • 代码优化

    • 可以将按钮和功能映射到字典中,减少代码重复。
    • 将历史记录保存到文件中,方便持久化存储。

实现步骤

  1. 设置焦点策略

    • __init__ 方法中设置 self.setFocusPolicy(Qt.StrongFocus),以确保窗口能够捕获键盘事件。
  2. 重写 keyPressEvent 方法

    • 创建一个字典 key_map,将按键与其对应的字符映射起
    • 来。
    • 根据按下的键,将相应的字符添加到 current_input 中,并更新显示区域。
    • 处理特殊键,如回车键(执行计算)、退格键(删除最后一个字符)、Escape键(清空输入)。
  3. 确保事件处理方法被调用

    • 确保 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 方法被正确重写,并且逻辑无误。
posted @   爱上编程技术  阅读(12)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示