本文将介绍一个基于 Python 的简单计算器系统,该系统可以进行加、减、乘、除等基本数学运算,并提供了一些额外的功能,如计算器历史记录、结果保存和导入等。本文首先介绍了系统的需求分析和概要设计,然后详细讨论了系统的实现和测试。最后,本文对系统进行了总结和展望。

第一章:绪论

1.1 选题背景和意义

计算器是一种广泛使用的电子设备,可用于进行各种数学运算。随着计算机技术的发展,现在的计算器已经发展成为了一种功能强大、体积小、使用简便的电子设备。特别是在教学、科研和日常生活中,计算器已经成为了必不可少的工具。

本文基于 Python 开发了一个简单计算器系统,旨在提供一种方便、快捷、易于使用的计算器工具,满足人们的计算需求。该系统不仅可以进行基本的数学运算,还提供了一些额外的功能,如计算器历史记录、结果保存和导入等,方便用户进行多次计算和查询。

1.2 计算器系统的需求分析

在设计计算器系统之前,首先需要进行需求分析,明确系统的功能和性能要求。本文的计算器系统要求具有以下功能:

(1)基本数学运算功能:加、减、乘、除等基本数学运算。

(2)科学计算功能:支持常用的科学计算函数,如 sin、cos、tan、log 等。

(3)计算器历史记录:记录用户进行过的计算过程和结果,方便用户进行查询和检索。

(4)结果保存和导入:允许用户将计算结果保存到本地文件,也允许用户从本地文件导入计算结果。

(5)用户友好界面:界面简洁、易于使用,允许用户进行自定义设置。

1.3 计算器系统的概要设计

在进行需求分析之后,需要进行概要设计,明确系统的结构和功能模块。本文的计算器系统采用了 MVC(Model-View-Controller)模式,将系统分为三个部分:模型、视图和控制器。

(1)模型:模型层负责数据的处理和管理,包括用户输入的数据、计算结果和历史记录等。在本文的计算器系统中,模型层采用了面向对象的方式实现,将计算器系统中的各个数据抽象成不同的对象,如数字对象、运算符对象、历史记录对象等。

(2)视图:视图层负责系统的用户界面,将模型层的数据以可视化的方式呈现给用户。在本文的计算器系统中,视图层采用了 tkinter 库实现,提供了一个简洁、美观、易于使用的用户界面。

(3)控制器:控制器层负责系统的逻辑处理,将视图层和模型层进行连接,实现用户界面和数据的交互。在本文的计算器系统中,控制器层采用了 Python 函数实现,将用户输入的数据传递给模型层进行计算,并将计算结果返回给视图层显示。

第二章:系统实现

2.1 系统环境和工具

本文的计算器系统采用 Python 语言进行开发,开发环境为 Windows 10 操作系统。以下是系统开发中所使用的主要工具和库:

(1)Python 3.7.4:Python 是一种高级编程语言,具有易于上手、灵活、可扩展等优点,是本文计算器系统的主要开发语言。

(2)tkinter 库:tkinter 是 Python 自带的 GUI(Graphical User Interface)库,提供了一组用于创建 GUI 应用程序的模块,是本文计算器系统的用户界面实现方式。

(3)pickle 库:pickle 是 Python 自带的序列化和反序列化库,可以将 Python 对象转换为二进制流,是本文计算器系统结果保存和导入的实现方式。

2.2 模型层的实现

模型层负责对用户输入的数据进行处理,并将计算结果返回给控制器层。在本文的计算器系统中,模型层采用了面向对象的方式实现,将计算器系统中的各个数据抽象成不同的对象。

2.2.1 数字对象的实现

数字对象用于保存用户输入的数字,可以进行加、减、乘、除等基本运算。在本文的计算器系统中,数字对象的实现如下:

class Number:
    def __init__(self, num):
        self.value = num

    def __add__(self, other):
        return Number(self.value + other.value)

    def __sub__(self, other):
        return Number(self.value - other.value)

    def __mul__(self, other):
        return Number(self.value * other.value)

    def __truediv__(self, other):
        return Number(self.value / other.value)

    def __str__(self):
        return str(self.value)

在数字对象的实现中,init 方法用于初始化数字对象,addsubmultruediv 方法用于实现数字对象的加、减、乘、除等基本运算,str 方法用于将数字对象转换为字符串。

2.2.2 运算符对象的实现

运算符对象用于保存用户输入的运算符,可以进行优先级比较。在本文的计算器系统中,运算符对象的实现如下:

class Operator:
    def __init__(self, op):
        self.value = op

    def __lt__(self, other):
        return self.priority() < other.priority()

    def __eq__(self, other):
        return self.priority() == other.priority()

    def priority(self):
        if self.value in ('+', '-'):
            return 1
        elif self.value in ('*', '/'):
            return 2
        elif self.value in ('(', ')'):
            return 0
        else:
            return -1

    def __str__(self):
        return str(self.value)

在运算符对象的实现中,init 方法用于初始化运算符对象,lteq 方法用于实现运算符对象的优先级比较,priority 方法用于返回运算符的优先级,str 方法用于将运算符对象转换为字符串。

2.2.3 历史记录对象的实现

历史记录对象用于保存用户进行过的计算过程和结果,可以进行保存和导入。在本文的计算器系统中,历史记录对象的实现如下:

class History:
    def __init__(self):
        self.history = []

    def add(self, expression, result):
        self.history.append((expression, result))

    def save(self, filename):
        with open(filename, 'wb') as f:
            pickle.dump(self.history, f)

    def load(self, filename):
        with open(filename, 'rb') as f:
            self.history = pickle.load(f)

    def __str__(self):
        return '
'.join([f'{expr} = {result}' for expr, result in self.history])

在历史记录对象的实现中,init 方法用于初始化历史记录对象,add 方法用于添加新的计算过程和结果,save 方法用于将历史记录保存到本地文件,load 方法用于从本地文件导入历史记录,str 方法用于将历史记录对象转换为字符串。

2.3 视图层的实现

视图层负责系统的用户界面,将模型层的数据以可视化的方式呈现给用户。在本文的计算器系统中,视图层采用了 tkinter 库实现,提供了一个简洁、美观、易于使用的用户界面。

2.3.1 用户界面的设计

本文的计算器系统的用户界面如下所示:

image

用户界面由两个部分组成:输入框和按钮。输入框用于显示用户输入的数据和计算结果,按钮用于进行各种操作,如数字输入、运算符输入、计算、清空、保存、导入等。

2.3.2 GUI 程序的实现

本文的计算器系统的 GUI 程序如下所示:

import tkinter as tk
from model import Number, Operator, History

class CalculatorGUI:
    def __init__(self):
        self.window = tk.Tk()
        self.window.title('Calculator')
        self.window.geometry('300x300')

        self.expression = tk.StringVar()
        self.result = tk.StringVar()

        self.history = History()

        self.create_widgets()

    def create_widgets(self):
        input_frame = tk.Frame(self.window)
        input_frame.pack(side=tk.TOP, padx=10, pady=10)

        tk.Entry(input_frame, textvariable=self.expression, width=25).pack(side=tk.LEFT)
        tk.Button(input_frame, text='C', width=5, command=self.clear).pack(side=tk.LEFT)

        button_frame = tk.Frame(self.window)
        button_frame.pack(side=tk.TOP, padx=10, pady=10)

        tk.Button(button_frame, text='1', width=5, command=lambda:self.add_digit('1')).grid(row=0, column=0)
        tk.Button(button_frame, text='2', width=5, command=lambda:self.add_digit('2')).grid(row=0, column=1)
        tk.Button(button_frame, text='3', width=5, command=lambda:self.add_digit('3')).grid(row=0, column=2)
        tk.Button(button_frame, text='+', width=5, command=lambda:self.add_operator('+')).grid(row=0, column=3)

        tk.Button(button_frame, text='4', width=5, command=lambda:self.add_digit('4')).grid(row=1, column=0)
        tk.Button(button_frame, text='5', width=5, command=lambda:self.add_digit('5')).grid(row=1, column=1)
        tk.Button(button_frame, text='6', width=5, command=lambda:self.add_digit('6')).grid(row=1, column=2)
        tk.Button(button_frame, text='-', width=5, command=lambda:self.add_operator('-')).grid(row=1, column=3)

        tk.Button(button_frame, text='7', width=5, command=lambda:self.add_digit('7')).grid(row=2, column=0)
        tk.Button(button_frame, text='8', width=5, command=lambda:self.add_digit('8')).grid(row=2, column=1)
        tk.Button(button_frame, text='9', width=5, command=lambda:self.add_digit('9')).grid(row=2, column=2)
        tk.Button(button_frame, text='*', width=5, command=lambda:self.add_operator('*')).grid(row=2, column=3)

        tk.Button(button_frame, text='0', width=5, command=lambda:self.add_digit('0')).grid(row=3, column=0)
        tk.Button(button_frame, text='.', width=5, command=lambda:self.add_digit('.')).grid(row=3, column=1)
        tk.Button(button_frame, text='(', width=5, command=lambda:self.add_operator('(')).grid(row=3, column=2)
        tk.Button(button_frame, text=')', width=5, command=lambda:self.add_operator(')')).grid(row=3, column=3)

        tk.Button(button_frame, text='/', width=5, command=lambda:self.add_operator('/')).grid(row=0, column=4)
        tk.Button(button_frame, text='%', width=5, command=lambda:self.add_operator('%')).grid(row=1, column=4)
        tk.Button(button_frame, text='^', width=5, command=lambda:self.add_operator('^')).grid(row=2, column=4)
        tk.Button(button_frame, text='=', width=5, command=self.calculate).grid(row=3, column=4)

        result_frame = tk.Frame(self.window)
        result_frame.pack(side=tk.TOP, padx=10, pady=10)

        tk.Label(result_frame, text='Result:').pack(side=tk.LEFT)
        tk.Entry(result_frame, textvariable=self.result, width=25, state='readonly').pack(side=tk.LEFT)

        history_frame = tk.Frame(self.window)
        history_frame.pack(side=tk.TOP, padx=10, pady=10)

        tk.Label(history_frame, text='History:').pack(side=tk.LEFT)
        tk.Button(history_frame, text='Save', command=self.save_history).pack(side=tk.LEFT, padx=10)
        tk.Button(history_frame, text='Load', command=self.load_history).pack(side=tk.LEFT, padx=10)

        self.history_text = tk.Text(history_frame, width=30, height=5, state='readonly')
        self.history_text.pack(side=tk.LEFT)

    def add_digit(self, digit):
        self.expression.set(self.expression.get() + digit)

    def add_operator(self, operator):
        self.expression.set(self.expression.get() + operator)

    def calculate(self):
        try:
            postfix = self.infix_to_postfix(self.expression.get())
            result = self.calculate_postfix(postfix)
            self.result.set(result)
            self.history.add(self.expression.get(), result)
            self.history_text.configure(state='normal')
            self.history_text.delete('1.0', tk.END)
            self.history_text.insert(tk.END, str(self.history))
            self.history_text.configure(state='readonly')
        except Exception as e:
            self.result.set('Error')

    def clear(self):
        self.expression.set('')
        self.result.set('')

    def infix_to_postfix(self, expression):
        postfix = []
        stack = []
        for token in expression:
            if token.isdigit() or token == '.':
                postfix.append(token)
            elif token == '(':                stack.append(token)            elif token == ')':                while stack[-1] != '(':                    postfix.append(stack.pop())                stack.pop()            else:                while len(stack) > 0 and stack[-1] != '(' and Operator(token) <= Operator(stack[-1]):                    postfix.append(stack.pop())                stack.append(token)        while len(stack) > 0:            postfix.append(stack.pop())        return postfix

    def calculate_postfix(self, postfix):        stack = []        for token in postfix:            if token.isdigit() or token.replace('.', '').isdigit():                stack.append(Number(float(token)))            else:                b = stack.pop()                a = stack.pop()                if token == '+':                    stack.append(a + b)                elif token == '-':                    stack.append(a - b)                elif token == '*':                    stack.append(a * b)                elif token == '/':                    stack.append(a / b)                elif token == '%':                    stack.append(Number(int(a.value) % int(b.value)))                elif token == '^':                    stack.append(Number(a.value ** b.value))        return str(stack[0])

    def save_history(self):        filename = tk.filedialog.asksaveasfilename()        if filename:            self.history.save(filename)

    def load_history(self):        filename = tk.filedialog.askopenfilename()        if filename:            self.history.load(filename)            self.history_text.configure(state='normal')            self.history_text.delete('1.0', tk.END)            self.history_text.insert(tk.END, str(self.history))            self.history_text.configure(state='readonly')

    def run(self):        self.window.mainloop()

if __name__ == '__main__':    app = CalculatorGUI()    app.run
基于 Python 的简单计算器系统设计与实现

原文地址: https://www.cveoy.top/t/topic/ntKE 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录