这个作业属于哪个课程 | https://bbs.csdn.net/forums/ssynkqtd-05 |
---|---|
这个作业要求在哪里 | https://bbs.csdn.net/topics/617294583 |
这个作业的目标 | 实现一个简易的计算器 |
其他参考文献 | 无 |
0. 任务:
完成一个具有可视化界面的计算器。
1.项目源码地址:
https://github.com/102101519/102101519
2.界面展示:
简单的乘法计算(如4*5=20)显示如下:
3.PSP表格:
PSP | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 10 | 10 |
• Estimate | • 估计这个任务需要多少时间 | 15 | 10 |
Development | 开发 | 50 | 70 |
• Analysis | • 需求分析 (包括学习新技术) | 100 | 100 |
• Design Spec | • 生成设计文档 | 60 | 60 |
• Design Review | • 设计复审 | 10 | 15 |
• Coding Standard | • 代码规范 (为目前的开发制定合适的规范) | 30 | 20 |
• Design | • 具体设计 | 40 | 40 |
• Coding | • 具体编码 | 300 | 300 |
• Code Review | • 代码复审 | 20 | 20 |
• Test | • 测试(自我测试,修改代码,提交修改) | 60 | 100 |
Reporting | 报告 | 60 | 60 |
• Test Repor | • 测试报告 | 20 | 20 |
• Size Measurement | • 计算工作量 | 10 | 10 |
• Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | 30 | 30 |
合计 | 815 | 865 |
4. 解题思路描述:
要求实现一个具有图形化界面的简易计算器
1.编程语言:在接到题目后,上网寻找了相关的描述,最终决定了使用较为简单实用的Python中的tkinter功能,实现界面化。虽然界面的美观度上限不如其他软件,但是可以实现基本的应用功能。
2.界面设计:在看了相关的描述后,明白了界面的设计包括了界面标题、结果显示、按钮显示等等,在设计好相关按钮后,还要为其调整位置和大小,使其变得更为美观。
3.功能实现:在设计好相关按钮后,需要正确地实现按钮功能的绑定,以及编写代码实现正确地运算。
4.完成打包:实现了基本功能的编写后,把Python转变成exe文件打包,使其可以在别的环境中成功运行。
5.设计与实现过程:
1.基本库的引用,界面的设计和关键变量的定义
import tkinter as tk
import math
from math import sqrt
root = tk.Tk()
root.title("计算器")
root.geometry('320x275+200+200')
root.attributes('-alpha',0.95)
root['background']='white'
result_num = tk.StringVar()
result_num.set('')
2.操作按钮的定义
def backspace():
opt_str = result_num.get()
new_str = opt_str[:-1]
result_num.set(new_str)
def dot():
result_num.set(result_num.get() + '.')
def square():
result =float(result_num.get())**2
result_num.set(str(result))
def square_root():
try:
result = sqrt(float(result_num.get()))
result_num.set(str(result))
except Exception as e:
result_num.set("Error:负数不能开方")
def calculation():
try:
opt_str =result_num.get()
result = eval(opt_str)
result_num.set(str(result))
except Exception as e:
result_num.set("Error:错误的数字格式")
def clear():
result=str('0')
result_num.set(str(result))
def click_button(btn_text):
opt_str = result_num.get()
if btn_text == '=':
try:
result = eval(opt_str)
result_num.set(str(result))
except Exception as e:
result_num.set("Error")
else:
try:
result_num.set(result_num.get() + btn_text)
except Exception as e:
result_num.set("Error")
3.按钮的设计,包括显示的名称,大小和字体等
result_entry = tk.Entry(root, textvariable=result_num,font=('宋体',30),width=10,justify=tk.LEFT)
result_entry.grid(row=0, column=0, columnspan=4)
button_0 = tk.Button(root, text="0",width=5,font=('宋体',20),bg='gray',command=lambda: click_button('0'))
button_0.grid(row=6, column=2)
button_1 = tk.Button(root, text="1",width=5,font=('宋体',20),bg='gray', command=lambda: click_button('1'))
button_1.grid(row=5, column=1)
button_2 = tk.Button(root, text="2",width=5,font=('宋体',20),bg='gray', command=lambda: click_button('2'))
button_2.grid(row=5, column=2)
button_3 = tk.Button(root, text="3",width=5,font=('宋体',20),bg='gray', command=lambda: click_button('3'))
button_3.grid(row=5, column=3)
button_4 = tk.Button(root, text="4",width=5,font=('宋体',20),bg='gray', command=lambda: click_button('4'))
button_4.grid(row=4, column=1)
button_5 = tk.Button(root, text="5",width=5,font=('宋体',20),bg='gray', command=lambda: click_button('5'))
button_5.grid(row=4, column=2)
button_6 = tk.Button(root, text="6",width=5,font=('宋体',20),bg='gray', command=lambda: click_button('6'))
button_6.grid(row=4, column=3)
button_7 = tk.Button(root, text="7",width=5,font=('宋体',20),bg='gray', command=lambda: click_button('7'))
button_7.grid(row=3, column=1)
button_8 = tk.Button(root, text="8",width=5,font=('宋体',20),bg='gray', command=lambda: click_button('8'))
button_8.grid(row=3, column=2)
button_9 = tk.Button(root, text="9",width=5,font=('宋体',20),bg='gray', command=lambda: click_button('9'))
button_9.grid(row=3, column=3)
button_plus = tk.Button(root, text="+",width=5,font=('宋体',20),bg='gray', command=lambda: click_button('+'))
button_plus.grid(row=5, column=4)
button_minus = tk.Button(root, text="-",width=5,font=('宋体',20),bg='gray', command=lambda: click_button('-'))
button_minus.grid(row=4, column=4)
button_multiply = tk.Button(root, text="*",width=5,font=('宋体',20),bg='gray', command=lambda: click_button('*'))
button_multiply.grid(row=3, column=4)
button_divide = tk.Button(root, text="/",width=5,font=('宋体',20),bg='gray', command=lambda: click_button('/'))
button_divide.grid(row=2, column=4)
button_equal = tk.Button(root, text="=",width=5,font=('宋体',20),bg='gray', command=calculation)
button_equal.grid(row=6, column=4)
button_decimal = tk.Button(root, text=".",width=5,font=('宋体',20),bg='gray', command=dot)
button_decimal.grid(row=6, column=3)
button_backspace = tk.Button(root, text="del",width=5,font=('宋体',20),bg='gray', command=backspace)
button_backspace.grid(row=2, column=3)
button_square = tk.Button(root, text="square",width=5,font=('宋体',20),bg='gray', command=square)
button_square.grid(row=2, column=2)
button_sqrt = tk.Button(root, text="sqrt",width=5,font=('宋体',20),bg='gray', command=square_root)
button_sqrt.grid(row=2, column=1)
button_clear = tk.Button(root, text="C",width=5,font=('宋体',20),bg='gray', command=clear)
button_clear.grid(row=6, column=1)
6.性能改进:
在进行平方运算的时候,本来设计为将输入字符串后面加上“**2”,然后按“=”进行计算,后面发现这样操作不美观,并且麻烦,于是直接将平方运算的结果输出。
7.单元测试:
单元测试代码如下:
import unittest
import calculator
class MyTestCase(unittest.TestCase):
def test_addtion(self):
calculator.clear()
calculator.click_button('3')
calculator.click_button('+')
calculator.click_button('2')
calculator.click_button('=')
result=calculator.result_num.get()
self.assertEqual(result,'5')
calculator.clear()
def test_dec(self):
calculator.clear()
calculator.click_button('10')
calculator.click_button('-')
calculator.click_button('2')
calculator.click_button('=')
result=calculator.result_num.get()
self.assertEqual(result,'8')
calculator.clear()
def test_mul(self):
calculator.clear()
calculator.click_button('5')
calculator.click_button('*')
calculator.click_button('3')
calculator.click_button('=')
result=calculator.result_num.get()
self.assertEqual(result,'15')
calculator.clear()
def test_div(self):
calculator.clear()
calculator.click_button('12')
calculator.click_button('/')
calculator.click_button('4')
calculator.click_button('=')
result=calculator.result_num.get()
self.assertEqual(result,'3.0')
calculator.clear()
def test_square(self):
calculator.clear()
calculator.click_button('8')
calculator.square()
result=calculator.result_num.get()
self.assertEqual(result,'64.0')
calculator.clear()
def test_square_root(self):
calculator.clear()
calculator.click_button('16')
calculator.square_root()
result=calculator.result_num.get()
self.assertEqual(result,'4.0')
calculator.clear()
if __name__ == '__main__':
unittest.main()
单元测试结果显示:
在进行单元测试的时候,将主代码的clear()算法中的清零变成了不显示任何数据,在每次单元测试的前后引入了这个函数,使得前后两次的计算不会互相影响。
8.错误处理:
1.在进行不合理的开方,如负数开方的时候,会进行准确报错"Error:负数不能开方"
2.我设计的计算器为输入完整的列式后按“=”进行计算,最初如果输入了奇怪的列式,例如03+02会出现崩溃,原因应该为不能正确处理字符串与数字之间的关系。在正常的书写过程中也不应该出现这种有前导0的计算,所以我进行了调整,如果出现了这种情况,将准确报错"Error:错误的数字格式"。
3.其他暂时还未知的错误情况都会被捕获并抛出普通异常"Error"。
9.心路历程与收获:
1.这是我进行的第一个软件开发,虽然开发的软件比较简单,完成了加减乘除的基本运算以及平方和开平方较为高级一些的运算,但是基础的功能和界面的设计也需要学习、设计很久。
2.虽然只使用了Python的tkinter进行前端的开发,但是也逐渐了解了前端三件套,初步了解了它们的长处和短处,有利于以后在学习和使用的时候选择合适的工具。
3.在这次的设计中采用了Python语言,在开发的过程中慢慢学习新知识,逐渐加深了对Python语言的掌握,有利于以后开发的时候继续使用,降低错误率。
4.在这次的开发中也逐渐学会了单元测试,学会编写测试的样例和预测。