用python实现可视化的科学计算器

文章目录

    • 作业要求
    • 项目源码地址
    • 0.界面及功能展示
    • 1.PSP表格
    • 2.解题思路描述
          • 1.编程语言选择:
          • 2.界面设计:
          • 3.核心功能:
          • 4.exe打包:
    • 3.核心代码
    • 4.设计和实现过程
    • 5.程序性能改进
    • 6.单元测试
    • 7.异常处理
    • 8.心路历程与收获


作业要求

作业链接

项目源码地址

源码的GitHub地址

0.界面及功能展示

科学计算器界面及其演示

1.PSP表格

PSP Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 20 10
•Estimate • 估计这个任务需要多少时间 20 30
Development 开发 70 70
• Design Spec • 生成设计文档 90 80
• Design Review • 设计复审 30 50
• Coding Standard • 代码规范 (为目前的开发制定合适的规范) 20 30
• Design • 具体设计 60 70
• Coding • 具体编码 180 220
• Code Review • 代码复审 60 30
• Test • 测试(自我测试,修改代码,提交修改) 100 100
Reporting 报告 80 100
• Test Repor • 测试报告 20 20
• Size Measurement • 计算工作量 10 10
• Postmortem & Process Improvement Plan • 事后总结, 并提出过程改进计划 30 30
合计 820 850

2.解题思路描述

1.编程语言选择:

选择Python作为开发语言,因为它在图形用户界面(GUI)开发方面有强大的库和框架支持,其中包括Tkinter、PyQt、wxPython等。Python也具有广泛的社区支持和丰富的文档资源,使得开发过程更加顺畅。

2.界面设计:

使用Python的Tkinter库可以创建直观且易于设计的图形用户界面。Tkinter提供了各种UI元素,如按钮、标签、文本框等,使得设计用户友好的UI变得容易,还可以利用Tkinter的布局管理器,例如grid、pack和place,来实现不同屏幕尺寸的适配和界面布局的灵活性。

3.核心功能:

Python是一门通用编程语言,可以轻松处理计算器的核心功能,包括接收用户输入、执行计算、显示结果等。
使用Python来实现基本的四则运算以及科学计算功能,如开方、取余、幂运算等,非常方便。
Python的字符串处理功能强大,可以轻松处理用户输入的表达式,进行计算,并生成结果。

4.exe打包:

可以使用Python的打包工具,如PyInstaller、cx_Freeze等,将Python脚本打包成独立的可执行文件(exe)。
这样,用户可以在没有安装Python解释器的情况下运行计算器,提供了更好的可移植性和用户体验。

综上所述,使用Python来实现图形化界面的简易计算器具有易用性、广泛的库支持、丰富的文档资源和跨平台能力等优势,使得它成为一个合适的选择。与前端技术不同,Python的Tkinter库可以在本地运行,无需依赖浏览器,并且更适合创建传统的桌面应用程序。因此我选择python来实现可视化的简易计算器。

3.核心代码

每次用户点击"back"按钮时,它会删除当前表达式中的最后一个字符,从而实现了一个逐步删除输入的功能。这在用户输入错误或者想要更改表达式时非常有用。例如,如果用户误输入了一个字符,可以通过点击"back"按钮来修复它,而不必清空整个表达式重新输入

    def back(self):
        temp_equ = self.equation.get()
        self.equation.set(temp_equ[:-1])  # 删除最后一个字符

根据用户的输入构建和更新计算表达式,同时处理一些语法规则和特殊函数的情况,以确保用户可以正确输入和编辑表达式

    def getNum(self, arg):
        temp_equ = self.equation.get()
        temp_result = self.result.get()

        # 判断基本语法错误
        if temp_result != ' ':  # 如果计算器之前没有结果,结果区域应该设置为空。
            self.result.set(' ')
        if temp_equ == '0' and (arg not in ['.', '+', '-', '*', '÷']):  # 如果首次输入为0,则后面不能是数字,只能是小数点或运算符
            temp_equ = ''
        if len(temp_equ) > 2 and temp_equ[-1] == '0':  # 运算符后面也不能出现0+数字的情况,如03,09,x
            if (temp_equ[-2] in ['+', '-', '*', '÷', '^']) and (
                    arg in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '(', 'π', 'e']):
                temp_equ = temp_equ[:-1]
        if arg in ['sin', 'cos', 'tan', 'sqrt', 'log']:
            temp_equ += arg + '('

        temp_equ += arg
        self.equation.set(temp_equ)

清除计算器界面上的表达式和结果,将它们恢复到初始状态,便于用户可以开始新的计算或输入新的表达式

    def clear(self):
        self.equation.set('0')
        self.result.set(' ')

用户在计算器界面上点击π或e按钮时,计算器将相应的数值插入到当前表达式中,以便用户可以继续构建表达式

    def insert_constant(self, constant):
        if constant == 'π':
            constant_value = str(math.pi)
        elif constant == 'e':
            constant_value = str(math.e)
        else:
            constant_value = ''

        temp_equ = self.equation.get()
        if temp_equ == '0':
            temp_equ = ''
        temp_equ += constant
        self.equation.set(temp_equ)

在用户点击计算器界面上的特殊函数按钮(如sin、cos、tan等)时,将相应的函数名插入到当前表达式中,以便用户可以继续构建表达式并在函数名后输入相应的参数

    def insert_function(self, func):
        temp_equ = self.equation.get()
        if temp_equ == '0':
            temp_equ = ''
        temp_equ += func
        self.equation.set(temp_equ)
    def run(self):
        temp_equ = self.equation.get()
        temp_equ = temp_equ.replace('÷', '/')  # 将÷替换为/
        temp_equ = temp_equ.replace('^', '**')
        temp_equ = temp_equ.replace('π', str(math.pi))  # 将π替换为math.pi
        temp_equ = temp_equ.replace('e', str(math.e))  # 将e替换为math.e
        if temp_equ[0] in ['+', '-', '*', '÷', '^']:
            temp_equ = '0' + temp_equ

4.设计和实现过程

1.导入必要的模块和库:
Tkinter库的各个模块
math库,用于处理数学运算和常数。

2.创建Calculator类:
通过定义一个名为Calculator的类,实现了计算器的功能和界面。

3.初始化主窗口:
在Calculator类的__init__方法中,创建了一个主窗口,并设置了窗口的标题、大小和不可调整大小。

4.创建样式:
使用ttk.Style()来创建窗口控件的样式,调整了按钮的外观和字体。

5.创建显示结果的文本框:
使用StringVar创建了两个文本变量,一个用于显示计算结果(self.result),另一个用于显示当前输入的表达式(self.equation)。
创建了两个Label控件来显示这两个文本变量,并设置它们的样式和对齐方式。

6.定义按钮和按钮样式:
创建了一个包含按钮文本、回调函数和样式的列表button_texts,其中包括数字按钮、运算符按钮和控制按钮。
使用循环将按钮按照指定的样式和回调函数放置到主窗口中。

7.设置网格权重:
使用循环为主窗口的行和列配置了权重,以便在调整窗口大小时,按钮可以根据窗口大小均匀分布。

8.放置结果显示文本框:
使用grid方法将结果显示文本框放置在主窗口的指定位置。

9.定义按钮回调函数:
在Calculator类中定义了一系列的按钮回调函数,包括数字按钮、运算符按钮、清除按钮、特殊函数按钮和计算按钮的回调函数。
这些函数用于处理用户的输入和执行计算。

10.运行主循环:
在if name == “main”:语句下,创建了Tkinter的根窗口,并实例化Calculator类,通过调用root.mainloop()来启动主循环,使计算器界面可以与用户进行交互。

总的来说,通过Tkinter库创建了一个简单的科学计算器界面,用户可以通过点击按钮输入数学表达式,然后计算结果会显示在界面上。各种按钮的回调函数处理了用户输入的不同情况,包括数字、运算符、特殊函数等,然后执行相应的计算。计算结果会显示在界面上的文本框中。

5.程序性能改进

错误处理:程序通过try…except块捕获可能的异常,如除零错误、语法错误和值错误。这提高了程序的健壮性,使其能够更好地处理用户输入错误或不合法的情况。
函数替换:程序在计算之前会检查表达式中是否包含特殊函数(如sin、cos、tan)等。如果有特殊函数,它会将这些函数替换为Python math模块中的对应函数,然后再计算表达式。这确保了特殊函数的正确计算。
常数替换:程序将用户输入的π和e替换为math.pi和math.e,以确保正确计算这些常数。
结果显示:程序使用%.4f格式化浮点数结果,保留四位小数,以提高结果的可读性。
按钮布局:按钮在GUI中的布局经过仔细设计,以确保它们在不同窗口大小下均匀分布,并且易于使用。

6.单元测试

对计算器的部分运算和特殊函数进行测试
测试代码

import unittest
from tkinter import Tk
from spq import Calculator


class TestCalculator(unittest.TestCase):

    def setUp(self):
        self.root = Tk()
        self.calculator = Calculator(self.root)

    def tearDown(self):
        self.root.destroy()

    def test_addition(self):
        # 测试加法运算
        self.calculator.getNum('2')
        self.calculator.getNum('+')
        self.calculator.getNum('3')
        self.calculator.run()
        self.assertEqual(self.calculator.result.get(), '5.0000')

    def test_subtraction(self):
        # 测试减法运算
        self.calculator.getNum('5')
        self.calculator.getNum('-')
        self.calculator.getNum('3')
        self.calculator.run()
        self.assertEqual(self.calculator.result.get(), '2.0000')

    def test_multiplication(self):
        # 测试乘法运算
        self.calculator.getNum('4')
        self.calculator.getNum('*')
        self.calculator.getNum('5')
        self.calculator.run()
        self.assertEqual(self.calculator.result.get(), '20.0000')

    def test_division(self):
        # 测试除法运算
        self.calculator.getNum('10')
        self.calculator.getNum('÷')
        self.calculator.getNum('2')
        self.calculator.run()
        self.assertEqual(self.calculator.result.get(), '5.0000')

    def test_power(self):
        # 测试幂运算
        self.calculator.getNum('2')
        self.calculator.getNum('^')
        self.calculator.getNum('3')
        self.calculator.run()
        self.assertEqual(self.calculator.result.get(), '8.0000')

    def test_logarithm(self):
        # 测试对数函数
        self.calculator.insert_function('log(')
        self.calculator.getNum('10')
        self.calculator.getNum(')')
        self.calculator.run()

        result_value = self.calculator.result.get()

        # 检查是否存在错误
        if result_value != 'Error':
            self.assertAlmostEqual(float(result_value), 2.3026, delta=0.001)
        else:
            self.assertEqual(result_value, 'Error')

    def test_square_root(self):
        # 测试平方根函数
        self.calculator.insert_function('sqrt(')
        self.calculator.getNum('25')
        self.calculator.getNum(')')
        self.calculator.run()

        result_value = self.calculator.result.get()

        # 检查是否存在错误
        if result_value != 'Error':
            self.assertEqual(result_value, '5.0000')
        else:
            self.assertEqual(result_value, 'Error')

    def test_error_divide_by_zero(self):
        # 测试除以零的错误
        self.calculator.getNum('5')
        self.calculator.getNum('÷')
        self.calculator.getNum('0')
        self.calculator.run()
        self.assertEqual(self.calculator.result.get(), 'Error')

    def test_special_functions(self):
        # 测试特殊函数
        self.calculator.insert_function('sin(')
        self.calculator.getNum('1')
        self.calculator.getNum(')')
        self.calculator.run()

        result_value = self.calculator.result.get()

        # 检查是否存在错误
        self.assertEqual(result_value, 'Error')

    def test_clear(self):
        # 测试清除功能
        self.calculator.getNum('7')
        self.calculator.clear()
        self.assertEqual(self.calculator.equation.get(), '0')
        self.assertEqual(self.calculator.result.get(), ' ')


if __name__ == '__main__':
    unittest.main()

7.异常处理

如果用户输入的表达式包含除零错误(ZeroDivisionError)、语法错误(SyntaxError)或值错误(ValueError),它会在结果文本框中显示"Error"。
如果没有出现以上异常,会尝试计算表达式:
使用eval()函数来计算表达式的值,并将结果格式化为四位小数。
如果计算成功,将结果显示在计算器的结果文本框中。
如果计算失败(例如,表达式不合法或包含不支持的操作),在结果文本框中显示"Error"。

 except (ZeroDivisionError, SyntaxError, ValueError):
                self.result.set(str('Error'))
        else:
            try:
                answer = '%.4f' % eval(temp_equ)
                self.result.set(str(answer))
            except (ZeroDivisionError, SyntaxError, ValueError):
                self.result.set(str('Error'))

结果如下:
用python实现可视化的科学计算器_第1张图片

8.心路历程与收获

在实现可视化的科学计算器的过程中,我遇到了许多的挑战,但也积累了许多经验和收获。

选择工具和技术:我考虑了多种语言,包括Java Swing、Python Tkinter以及前端技术(HTML、CSS、JavaScript)。最终,我选择了Python Tkinter,因为它在Python中集成,易于上手,而且python是相较于前端技术和Java我比较熟悉的语言,尽管前端技术能够实现更加优美的界面,但是我对这项技术不够熟悉最终放弃了这个选项。

界面设计:设计一个直观且美观的用户界面是并不是容易的,代码不仅能够实现一些特定的功能,还要界面足够的美观去吸引用户使用,我参考了一些现有的计算器界面,学到了如何使用颜色、字体和布局来创建吸引人的界面。

错误处理和异常处理:在开发这个计算器时,我认识到错误处理和异常处理的重要性。用户可以输入各种不同的表达式,可能导致各种异常情况。因此,我学会了使用try…except块来捕获这些异常,并提供友好的错误消息,以确保程序的健壮性。

数学函数和常数的处理:支持特殊函数(如sin、cos、tan)以及数学常数(π和e)是这个计算器的关键功能之一。我学习了如何在用户输入中识别这些函数和常数,以及如何将它们转换为可计算的形式。这个过程加深了我对Python中数学模块的了解。

布局和窗口自适应:我花了一些时间来设计按钮的布局,以确保它们能够在不同窗口大小下均匀分布。这个经验使我更熟悉了Tkinter中的网格布局和权重分配。

可维护性和扩展性:在开发过程中,我努力保持代码的可维护性和扩展性。我将代码模块化,确保每个函数和方法都有清晰的责任,这使得在将来添加新功能或修复错误时更加容易。

你可能感兴趣的:(python,开发语言)