软件工程第二次作业
一、四则运算小程序要求
(1)能够自动生成四则运算练习题
(2)可以定制题目数量
(3)用户可以选择运算符
(4)用户设置最大数(如十以内、百以内等)
(5)用户选择是否有括号、是否有小数
(6)用户选择输出方式(如输出到文件、打印机等)
(7)生成小程序,即提供用户页面
二、代码地址
代码仓库地址:https://github.com/yyp-30/yyp/tree/master
exe文件地址:链接:https://pan.baidu.com/s/1QjMqBYJMSidJQYbLm5wA4g 提取码:gc4s
三、解决思路
首先,先建立一个合适的数据结构,用来表达四则运算这种算式。应该有数,算式符号和括号这些元素的具体值和位置等属性。我决定使用数组这个数据结构来存储这些信息。
其次,需要考虑如何生成这样一个描述算式的数据结构。需要先随机确定有几个数参与运算,然后根据给定的数的最大值确定具体每个数的大小。我们还需要随机确定每两个数之间的运算符号是什么。接着,我们应该随机确定应该有几个括号和括号的位置。
最后,根据符号的约束规则,随机生成这些符号和其位置。 最后,用一个函数,将生成好的数据结构信息,“翻译”为算式去展示。
四、具体代码
(1)生成运算式的类
# -*- coding: utf-8 -*- """ @File : Calculation.py 生成运算类 """ import random # 一个数据结构 class stru(): def __init__(self): self.num_count = 0 # 数的个数 self.num_result_count = 0 self.num_arr = [] # 数的数组 self.bra_arr = [] # 括号的数组 self.brackets = 0 # 括号的数目 self.sym = [] # 符号的数组 self.sym_arr = [] # 符号的存储 self.sym_count = 0 # 符号的数目 self.result = 0 class ger(): def gen_que(self, count, max_num, dec, sym, bra, fileout, num_cal_count): ''' :param count:要出的题目数 :param max_num:最大数 :param dec:是否有小数 :param sym:运算符号 :param bra:是否有括号 :param fileout:输出方式 :param num_cal_count:最多几个数运算 :return: ''' result = "" mystru = stru() # 实例化一个stru类 for i in range(count): mystru.__init__() mystru.num_count = random.randint(2, num_cal_count) mystru.num_result_count = mystru.num_count mystru.sym = sym mystru.sym_count = mystru.num_count - 1 if dec: # 有小数的情况下 for i in range(mystru.num_count): if random.randint(0, 1): mystru.num_arr.append(round(random.uniform(1, max_num), 1)) # 取一位精度 else: mystru.num_arr.append(random.randint(1, max_num)) else: # 整数情况 for i in range(mystru.num_count): mystru.num_arr.append(random.randint(1, max_num)) for i in range(mystru.sym_count): # 生成运算符号 mystru.sym_arr.append(random.choice(sym)) if bra: # 生成括号 self.genet_bra(mystru) result = result + self.print_que(mystru) + " " # print(self.print_que(mystru) + str(mystru.bra_arr) + " ") return result def print_que(self, stru): """ 根据stru生成一个算式,stru中有必要的原料 :param stru:输入一个算式结构 :return:str """ que = "" for i in range(stru.num_count + 1): if i == 0 and (self.judege_bra(stru, 1, 0)): que = que + "(" * self.judege_bra(stru, 1, 0) + str(stru.num_arr[0]) elif i == 0 and (not self.judege_bra(stru, 1, 0)): que = que + str(stru.num_arr[0]) elif i == stru.num_count and (self.judege_bra(stru, stru.num_count, 1)): que = que + ")" * self.judege_bra(stru, stru.num_count, 1) + "=" elif i == stru.num_count and (not self.judege_bra(stru, stru.num_count, 1)): que = que + "=" else: if self.judege_bra(stru, i, 1): que = que + ")" * self.judege_bra(stru, i, 1) que = que + stru.sym_arr[i - 1] if self.judege_bra(stru, i + 1, 0): que = que + "(" * self.judege_bra(stru, i + 1, 0) que = que + str(stru.num_arr[i]) return que def judege_bra(self, stru, posi, left_right): """ 判断括号是否存在 :param stru: :param posi: :param left_right:位于一个数的左边0,还是右边1 :return:int 代表出现了几次 """ count = 0 for i in range(stru.brackets): if stru.bra_arr[i][left_right] == posi: count = count + 1 return count def genet_bra(self, stru): """ 生成括号数组 :param stru:输入一个stru结构 :return: """ brackets = stru.num_count - 2 stru.brackets = random.randint(0, brackets) # 括号数目 while True: stru.bra_arr = [] for i in range(stru.brackets): while True: temp_list = random.sample([j for j in range(1, stru.num_count + 1)], 2) # 随机选两个数作为括号 temp_list.sort() # 对列表排序 if (temp_list[0] == 1) and (temp_list[1] == stru.num_count): # 括号无意义 continue elif self.list_repeat(stru.bra_arr, temp_list): # 括号查重 continue else: stru.bra_arr.append(temp_list) break if self.jude_bra_valid(stru): break def list_repeat(self, list1, list2): """ 括号去重 :param list1:stru中的括号数组 :param list2: :return: """ for i in range(len(list1)): if (list1[i][0] == list2[0]) and (list1[i][1] == list2[1]): return True if (list1[i][1] == list2[0]) or (list1[i][0] == list2[1]): return True return False def jude_bra_valid(self, stru): """ 判定括号是否合法 :param stru: :return:bool """ if stru.brackets == 1: return True else: stru.bra_arr.sort(key=self.get_list_subtract) # 对数组排序 stru.bra_arr.sort(key=self.get_list_fir) # 再次排序 for i in range(stru.brackets - 1): for j in range(i + 1, stru.brackets): if (stru.bra_arr[i][1] > stru.bra_arr[j][0]) and ( stru.bra_arr[i][0] < stru.bra_arr[j][0]) and ( stru.bra_arr[i][1] < stru.bra_arr[j][1]): return False return True def get_list_subtract(self, lst): """ 返回数组中第二个和第一个的差 :param lst: :return: """ return lst[1] - lst[0] def get_list_fir(self, lst): """ 返回数组中的第一个值 :param lst: :return: """ return lst[0]
(2)主控程序类
# -*- coding: utf-8 -*- """ @File : deal.py 主控程序类 """ from PyQt5 import QtCore, QtGui, QtWidgets from untitled import Ui_MainWindow from child import Ui_Dialog from PyQt5.QtWidgets import QMessageBox import sys from Calculation import ger class Mywindow(QtWidgets.QMainWindow, Ui_MainWindow): def __init__(self): """ 完成GUI初始化工作,绑定槽 """ super(Mywindow, self).__init__() self.setupUi(self) # 初始化GUI控件 self.horizontalSlider.valueChanged[int].connect(self.horizon_changeValue) self.horizontalSlider_2.valueChanged[int].connect(self.horizon2_changeValue) self.pushButton.clicked.connect(self.pushbutton_clich) self.child_dia = Mydialog() def pushbutton_clich(self): try: if self.check_inpue_valid(): count = int(self.lineEdit_2.text()) max_num = self.horizontalSlider.value() dec = self.checkBox.isChecked() bar = self.checkBox_2.isChecked() out = self.radioButton.isChecked() sym = self.get_sym() num_cal_count = self.horizontalSlider_2.value() mygerne = ger() # 实例化一个ger对象 pri_str = mygerne.gen_que(count, max_num, dec, sym, bar, out, num_cal_count) # 调用生成算式的函数 info.STR = pri_str if out: # 输出到文件 self.fileout(pri_str) QMessageBox.information(self, "提示信息", "已生产文件,文件名为‘que.txt’", QMessageBox.Yes) else: # 屏幕显示 self.child_dia.set_textbro() self.child_dia.exec_() except Exception as e: print(e) def fileout(self, t_str): with open("que.txt", "w", encoding="utf8") as f: f.write(t_str) # 检查输入是否合法 def check_inpue_valid(self): if self.lineEdit_2.text() == '' or int(self.lineEdit_2.text()) == 0: QMessageBox.warning(self, "警告信息", "题目数量数据不合法", QMessageBox.Yes) return False if self.horizontalSlider.value() == 0: QMessageBox.warning(self, "警告信息", "最大数不合法", QMessageBox.Yes) return False if not self.get_sym(): QMessageBox.warning(self, "警告信息", "至少选择一个运算法则", QMessageBox.Yes) return False return True # 获取选择的运算符 def get_sym(self): sym_list = [] if self.checkBox_3.isChecked(): sym_list.append('+') if self.checkBox_4.isChecked(): sym_list.append('÷') if self.checkBox_5.isChecked(): sym_list.append('-') if self.checkBox_6.isChecked(): sym_list.append('×') return sym_list def horizon_changeValue(self, value): self.label_3.setText(str(value)) def horizon2_changeValue(self, value): self.label_5.setText(str(value)) # 子窗口 class Mydialog(QtWidgets.QDialog, Ui_Dialog): def __init__(self): super(Mydialog, self).__init__() self.setupUi(self) def set_textbro(self): self.textBrowser.setLineWrapMode(QtWidgets.QTextEdit.NoWrap) # textBrowser要想正常显示水平滚动条,必须将lineWrapMode设置为nowrap self.textBrowser.setText(info.STR) # 设置文本浏览器 if __name__ == "__main__": app = QtWidgets.QApplication(sys.argv) myshow = Mywindow() myshow.show() sys.exit(app.exec_())
五、结果显示
mainwindow窗体显示
题目窗口弹出:
六、总结
PyQt5是基于图形程序框架Qt5的Python语言实现,由一组Python模块构成。
此作业是初次接触PyQt5,不太熟悉PyQt5的应用,应加强学习。
七、psp表格
psp | 任务内容 |
计划完成需要的时间(min) | 实际完成需要的时间(min) |
Planning | 计划 | 50 | 60 |
Estimate | 估计这个任务需要多少时间,并规划大致工作步骤 | 20 | 30 |
Analysis | 需求分析 (包括学习新技术) | 60 | 90 |
Design | 具体设计 | 50 | 60 |
Coding | 具体编码 | 400 | 500 |
test | 测试(自我测试,修改代码,提交修改) |
200 | 250 |
Postmortem & Process Improvement Plan |
事后总结 ,并提出过程改进计划 | 30 | 50 |
Summary | 合计 | 810 | 1040 |