title: 南京邮电大学电院软件设计 tags: categories:
- 软件设计
index_img: https://w.wallhaven.cc/full/72/wallhaven-72637v.jpg
banner_img: https://w.wallhaven.cc/full/72/wallhaven-72637v.jpg
date: 2021-4-29 10:00<00>00> excerpt: 南京邮电大学电院软件设计
前言:
终于写完了软件设计,打算为这段时间的经历写一篇博客,意在记录生活。我想看到这篇文章的同学都抱有不同的目的,我想大部分人是想找个能用的程序混过这次软件设计,毕竟大三下才安排,这段时间都在忙着考研,怀着这份想法的同学可能要失望了,目前代码不打算完全公开。不过我公开了期中的关键部分,还有一些无关紧要的部分没有被公开,比如GUI的源文件,如果你会PYQT的话,这部分看了GUI设计就可以非常轻松复原出来的。
我希望同学们可以像我一样自学python+pyqt,真正掌握这门技术,然后再读这篇文章,靠它来辅助你完成软件设计,当然学懂后如果你想偷懒,也是可以直接复制我的工程,删删改改后就成为自己的了。
软件设计必然会涉及到评优的问题,同学们如果看见有人复原出来了我的程序,并拿到了优。我非常瞧不起这人啊,干他!
吐槽下:都2022年了,南邮软件设计的题目为什么还是2011年的,我还专门去查了长途话费应该怎么算。不过对于能力的提升效果还是可以的,题目的应用背景只是一个躯壳。

软件设计心得
因为疫情问题,软件设计被定在了线上进行,听说往年的软件设计是小组完成,这次为单人完成,颇具挑战性。查看了题目,发现就我已经掌握的语言:C和JAVA比较难以应对这种面向对象的题目(JAVA面向,但我学的浅不太熟),同时我就想,如果我使用C语言完成这次软件设计,对自己会有多少提高呢?完成的效果会怎么样呢?思前想后,我决定学习一门新的语言,能够非常好的处理对象问题。C++或者python是不错的选择,考虑到未来可能会跟机器学习打交道,机器学习使用的python居多,同时python在很多场景下都有应用,比如数学建模、绘图等;其次C++我是学过基础的,总的感觉和C相似(当然C++不是C,他们只是基础部分有一定交集)。还有GUI的考虑,C++可以直接开发QT,这一点我之前就知道的,网上查了下python也支持,不过它叫做PYQT专门为python设计的,这么看GUI的问题也有着落。综合考虑后选择了python。语言光学不练,等于没学,正好借这次机会练练手。 下面是时间的规划,10天的时间要自学完python和pyqt,同时还要完成7道不大不小的题目。时间上还是比较急的,具有挑战性。不过这不正合我意吗?我就喜欢走不寻常的路,不仅可以学习到更多的东西,见到别人没见过的风景,还可以有心跳、激情。10天安排如下:6天自学python、1天自学pyqt,3天写完程序。其中pyqt学1天肯定不够,主要是配置开发环境和懂得基础使用,很多内容还是要在后面3天写程序的过程中碰到问题针对性的去学习。 6天自学python真的绰绰有余,可能是我之前有小学过一段时间,这次从头学习的过程行云流水,非常顺利;这期间我顺便把一拳超人的一二集全刷完了。掌握的也不错,大一自学C语言的时候摸索出了一套适合自己的学习方法:学中练、练中学,沉得住气,才能干得过BUG。 整个程序开发基本上是一个人完成的,除了有两个BUG实在不知道怎么解决了,网上也没有合适的解答,求助同学。开发过程中碰到了不少BUG,不少都在CSDN等技术性网站上找到答案了,不好找啊,里面许多内容不是具有局限性,就是版本太老了,完全没有参考价值;自学一些模块的时候挑选教程也叫我一阵好找,内容太老了,质量也参差不齐,对比国外的技术性网站,CSDN等国内技术网站还有很多路要走啊! 两周的小学期即将结束,时间虽短,但是我收获了很多。谢谢老师和同学们的指导。最后非常感谢软件设计,自从电赛结束后,我很久没有这样为了某个明确的目标而努力,不遗余力,战的热血沸腾哈哈哈哈哈哈,最后三天写程序时,身边的同学不管用什么样的方法吧,不是已经做完了,就是还差个1-2题,而我还没开动,慌张感驱动着我从早到凌晨不停的写,最后一天直接写到凌晨2点多。充实!
分数统计软件(A1)
设计题目及要求
设计一个分数统计程序。包括学生信息的输入输出以及排序。通过该课题全面熟悉数组、字符串、文件的使用,掌握程序设计的基本方法及友好界面的设计。 (1)输入某班级学生的姓名、分数; (2)对(1)的分数进行降幂排列并输出; (3)具有输入输出界面。
设计思想及程序流程框图
题目的意思是可以输入一个学生信息,具体是学生的姓名信息和成绩信息,可以选择性的存入,也就是要有一个存入的按钮选项。当输入完成后呢,可以排序输出。
UI设计

上面是我根据题目要求设计出来的,可以发现总共需要如上图内容所示的几个控件,首先是两个文本输入控件(这里用的是QT里面的QLineEdit)分别用来输入姓名和成绩。
放置“存入”按键,当按下时程序会进入一个函数,我们在这个函数里面存下姓名和成绩信息。
放置“排序并显示”按键,当被按下时程序会进入display_inf()函数,函数内会依据学生的成绩信息进行排序,并显示在右边的qtextedit控件。
程序设计
数据结构:
这题比较easy,一个学生对象就可以安排好。属性和方法如图所示。

在管理数据时,只需要定义一个列表,每存入一个学生,就把他当作对象存入列表就可以了。
服务函数:
当“存入”按键被按下时,触发save_issue()函数,函数内读取姓名、成绩文本框内的内容,存储到学生列表中。
当“清空”按键被按下时,会触发clearStudent()函数,函数内清空已经存储的学生列表和当前页面所有的显示信息。
当“排序并显示按钮被按下时”,会触发display_inf()函数,函数内首先根据学生的成绩对学生列表进行排序,之后依次显示。

逻辑功能程序
main.py
# PyQt5中使用的基本控件都在PyQt5.QtWidgets模块中from PyQt5.QtWidgets import QApplication, QMainWindow# 导入程序运行必须模块import sys# 导入designer工具生成的login模块from qs11 import Ui_MainWindow# 导入自定义的类from student import *from functools import partialimport operator # 用于排序的包from PyQt5 import QtCorefrom qt_material import apply_stylesheet
all_student = [] # 存放所有的学生
class MyMainForm(QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super(MyMainForm, self).__init__(parent) self.cursot = None self.setupUi(self) self.save_button.clicked.connect(partial(self.save_issue)) self.dis_button.clicked.connect(partial(self.display_inf)) self.clear_counter.clicked.connect(partial(self.clearStudent))
# 存储学生信息 def save_issue(self): person = student() person.setName(self.user_line.text()) person.setGrade(int(self.grade_line.text())) all_student.append(person)
self.user_line.clear() self.grade_line.clear()
def printf(self, mes): self.inf_dis.append(mes) # 在指定的区域显示提示信息 self.cursot = self.inf_dis.textCursor() self.inf_dis.moveCursor(self.cursot.End)
def display_inf(self): # 排序 cmpfun = operator.attrgetter('grade', 'name') all_student.sort(key=cmpfun, reverse=True) # 清空上次显示的内容 self.inf_dis.clear() # 显示当前排序好后的内容 for i in range(len(all_student)): self.printf("%s %d" % (all_student[i].name, all_student[i].grade))
# 清空存储的学生信息 def clearStudent(self): self.user_line.clear() self.grade_line.clear() self.inf_dis.clear() all_student.clear()
if __name__ == '__main__': QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling) # 解决页面显示不一致的问题 app = QApplication(sys.argv)
myWin = MyMainForm() apply_stylesheet(app, theme='dark_red.xml') myWin.show()
sys.exit(app.exec_())student.py
class student: def __init__(self): self.grade = None # 用户成绩 self.name = ' ' # 用户姓名
# 设置成绩 def setGrade(self, grade): self.grade = grade
# 设置姓名 def setName(self, name): self.name = name结果及完善方向

打字软件(A2)
设计题目及要求
设计一个打字程序。包括随机产生字符串,以及字符串比较和统计。通过此课题,熟练掌握数组、格式输出、字符串处理等。
(1)随机产生一字符串,每次产生的字符串内容、长度都不同;
(2)根据(1)的结果,输入字符串,判断输入是否正确,输出正确率;
(3)具有输入输出界面。
设计思想及程序流程框图
UI设计

程序设计思路
编写一个程序生成随机数,由随机数产生一个包含阿拉伯数字、大写字母、小写字母的字符串,输出到界面。键入字符串,回车后,调用比较函数,判断是否输入正确,在右下角的方框中提示正确与否,同时中下方的进度条会将正确率转换成对应的进度进行显示。
程序流程框图:

逻辑功能程序
# PyQt5中使用的基本控件都在PyQt5.QtWidgets模块中from PyQt5.QtWidgets import QApplication, QMainWindowfrom PyQt5 import QtCore# 导入程序运行必须模块import sys# 导入designer工具生成的login模块from qus12 import Ui_MainWindowfrom functools import partialimport randomfrom qt_material import apply_stylesheet
num_all = 0 # 总共输入的次数num_cor = 0 # 正确输入的次数
# 获取随机字符串def GetRandomStr(): lst = random.sample('zyxwvutsrqponmlkjihgfedcba', random.randint(1, 10)) s2 = "".join([str(e) for e in lst]) # 使用空字符串拼接字符串列表 return s2
class MyMainForm(QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super(MyMainForm, self).__init__(parent) self.cursot = None self.setupUi(self) self.bar.setMaximum(100) self.bar.setMinimum(0) self.bar.setValue(100) self.rightnot.append("") self.lineEdit.setText(GetRandomStr()) self.lineEdit_2.returnPressed.connect(partial(self.input_call)) self.clear_button.clicked.connect(partial(self.clear_app))
# 当输入完成并敲击回车后,调用此函数 def input_call(self): global num_all global num_cor num_all += 1 str1 = self.lineEdit.text() str2 = self.lineEdit_2.text() # 比较是否正确 if str1 == str2: num_cor += 1 self.rightnot.setText("正确") else: self.rightnot.setText("错误") # 显示正确率 self.accuracy.setText("%2.1f" % (num_cor * 100 / num_all) + '%') self.bar.setValue((num_cor * 100 / num_all)) # 更新随机字符串 self.lineEdit.setText(GetRandomStr()) self.lineEdit_2.clear()
# 清空屏幕和归零正确率 def clear_app(self): global num_all global num_cor self.lineEdit_2.clear() self.rightnot.clear() self.accuracy.clear() num_all = 0 num_cor = 0
if __name__ == '__main__': QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling) app = QApplication(sys.argv)
myWin = MyMainForm() apply_stylesheet(app, theme='dark_red.xml') myWin.show()
sys.exit(app.exec_())结果及完善方向

文本编辑器(A3)
设计题目及要求
设计一个简单的文本编辑器,该系统要求对一个文本文件中的内容进行各种常规操作,如:插入、删除、查找、替换等功能。通过此课题,熟练掌握文本文件的操作及用字符数组或字符指针实现字符串操作的功能。
(1)编辑文本;
(2)保存、打开指定位置的文本文件;
(3)具有输入输出界面。
设计思想及程序流程框图
UI设计:

程序思路:
设计一个路径输入框,当点击”打开“时,程序读取相应位置的文件,将文章内容显示在文本框中,文本框控件为qtextedit,支持直接编辑,方便了用户修改,编辑完成后点击”写入“整个修改过程就完成了。

逻辑功能程序
import sys# PyQt5中使用的基本控件都在PyQt5.QtWidgets模块中from PyQt5.QtWidgets import QApplication, QMainWindow# 导入程序运行必须模块import sys# 导入designer工具生成的login模块from qus13 import Ui_MainWindowfrom PyQt5 import QtCorefrom functools import partialimport osfrom qt_material import apply_stylesheet
class MyMainForm(QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super(MyMainForm, self).__init__(parent) self.cursot = None self.setupUi(self) self.f = '' self.open_file.clicked.connect(partial(self.input_path)) self.write_file.clicked.connect(partial(self.write_content))
def input_path(self): if os.path.exists(self.path_edit.text()): with open(self.path_edit.text(), 'r+') as self.f: self.textEdit.setText('') for str in self.f.readlines(): self.printf(str) self.f.close() else: open(self.path_edit.text(), 'w')
def printf(self, mes): self.textEdit.insertPlainText(mes) # 在指定的区域显示提示信息
def write_content(self): with open(self.path_edit.text(), 'r+') as self.f: self.f.truncate() self.f.writelines(self.textEdit.toPlainText()) self.f.close()
if __name__ == '__main__': QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling) app = QApplication(sys.argv)
myWin = MyMainForm() apply_stylesheet(app, theme='dark_red.xml') myWin.show()
sys.exit(app.exec_())结果及完善方向

加密软件(A4)
设计题目及要求
设计一个加密程序。包括明文与密钥的转换。通过此课题,熟练掌握数组、格式输出、字符串处理、类型转换等。
(1)输入任意一段明文M,以及密钥K;
(2)根据以下公式将其转换为密文C。
Ci = mi + K ,其中i = 0,1,……n-1 , K 为密钥;
(3)具有输入输出界面。
设计思想及程序流程框图
UI设计:

程序思路:
设计两个输入框,供用户输入明文和密钥,当输入完成,点击转换,转换结果就会在下方的文本框中显示。

逻辑功能程序
# PyQt5中使用的基本控件都在PyQt5.QtWidgets模块中from PyQt5.QtWidgets import QApplication, QMainWindow# 导入程序运行必须模块import sys# 导入designer工具生成的login模块from qus14 import Ui_MainWindowfrom PyQt5 import QtCorefrom functools import partialfrom qt_material import apply_stylesheet
# str应为字符串,k为整数# 返回加密后的字符串def encrypt(str, k): lis = [] for i in range(len(str)): lis.append(str[i]) lis[i] = chr(ord(lis[i]) + k) return "".join([e for e in lis])
class MyMainForm(QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super(MyMainForm, self).__init__(parent) self.cursot = None self.setupUi(self) self.conv.clicked.connect(partial(self.my_conversion))
def my_conversion(self): self.textEdit.clear() # 清空上次的显示
# 更新新的显示 str = self.line1.text() K = int(self.line2.text()) str_dis = encrypt(str, K)
self.textEdit.append(str_dis)
if __name__ == '__main__': QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling) # 解决页面显示不一致的问题
app = QApplication(sys.argv)
myWin = MyMainForm() apply_stylesheet(app, theme='dark_red.xml') myWin.show()
sys.exit(app.exec_())结果及完善方向

进制转换器(A5)
设计题目及要求
设计一个进制转换器程序。包括二进制、八进制、十进制、十六进制数互相转换。通过此课题,熟练掌握字符串、格式输出、进制换算的各种操作。
(1)可输入二进制、八进制、十进制、十六进制数;
(2)将已输入的数转换成其余进制的数;
(3)具有输入输出界面。
设计思想及程序流程框图
UI:

程序设计思路
用户可以选择原始和目标的进制,选择完成后在文本框输入原始数据,接着点击转换,就可以得到转换完成后的数据。如果用户输入错误,程序会输出”输入错误“提示用户重新输入。

逻辑功能程序
# PyQt5中使用的基本控件都在PyQt5.QtWidgets模块中from PyQt5.QtWidgets import QApplication, QMainWindow# 导入程序运行必须模块import sys# 导入designer工具生成的login模块from qus15 import Ui_MainWindowfrom PyQt5 import QtCorefrom functools import partialfrom qt_material import apply_stylesheet
class MyMainForm(QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super(MyMainForm, self).__init__(parent) self.setupUi(self)
# 变量定义 self.ori_sys = 0 # 原始进制格式 self.tar_sys = 0 # 目标进制格式 self.origin_sys = 0 # 原始进制格式的十进制表示
self.target_dis = '' # 用于进行显示的字符串 # 信号事件定义 self.cb1.currentIndexChanged.connect(partial(self.cb1_call)) self.cb2.currentIndexChanged.connect(partial(self.cb2_call)) self.conv.clicked.connect(partial(self.conv_call))
def cb1_call(self): self.ori_sys = self.cb1.currentIndex() # print("原始进制为:%d" % self.ori_sys)
def cb2_call(self): self.tar_sys = self.cb2.currentIndex() # print("目标进制为:%d" % self.tar_sys)
def conv_call(self): # 统一进制表示 if self.ori_sys == 0: self.origin_sys = 2 elif self.ori_sys == 1: self.origin_sys = 8 elif self.ori_sys == 2: self.origin_sys = 10 else: self.origin_sys = 16 try: origin = int(self.line1.text(), self.origin_sys)
if self.tar_sys == 0: self.target_dis = bin(origin) elif self.tar_sys == 1: self.target_dis = oct(origin) elif self.tar_sys == 2: self.target_dis = origin else: self.target_dis = hex(origin)
self.line2.setText(str(self.target_dis)) except ValueError: self.line2.setText("输入错误")
if __name__ == '__main__': QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling) # 解决页面显示不一致的问题
app = QApplication(sys.argv)
myWin = MyMainForm() apply_stylesheet(app, theme='dark_red.xml') myWin.show()
sys.exit(app.exec_())结果及完善方向
正确输入效果:

错误输入效果:

完善方向:
可以尝试做成win自带的进制转换方式,输入一个目标进制后,可以通过选择其他进制实现转换。(描述不好,来看图吧)

学生成绩核算系统的设计与实现(B1)
设计题目及要求
设计一个学生成绩核算系统。能实现从文件中读取学生成绩资料,并提供成绩查询统计服务。通过此课题,熟练掌握文件、数组、结构体的各种操作以及友好界面的设计。 (1)按班级按课程从文件中读入相应的平时成绩、期中考试成绩和期末考试成绩。 (2)三个成绩对总评成绩的百分比被定义为常数,各占总成绩的30%、30%和40%。 (3)计算每位学生的总评成绩。 (4)计算该班级本课程的总平均成绩。 (5)计算处于优、良、中、及格、不及格的学生人数以及占总人数的百分比。其中100-90为优,89-80为良,79-70为中,69-60为及格,60分以下为不及格。 (6)按要求输出成绩在优、良、中、及格、不及格各区间的学生学号、成绩。
设计思想及程序流程框图
UI设计:

第一行从左往右依次为:学科选择(QComboBox 控件,这边举了模电、数电两门课程)、班级选择(QComboBox 控件)、等地选择(QComboBox 控件)、刷新按键。
程序设计:
1、建立excel表格,根据课程数量为每一个课程建立一份表单,为了方便展示,这边分别为”模电“、”数电“。
以模电表格为例,每一行存储学生信息,分别为:姓名、班级、学号、平时成绩、期中成绩、期末成绩。
| 姓名 | 班级 | 学号 | 平时成绩 | 期中成绩 | 期末成绩 |
|---|---|---|---|---|---|
| 落 | B190207 | 994201 | 88 | 75.5 | 66 |
| 霞 | B190207 | 994202 | 91 | 79.5 | 76 |
| 与 | B190207 | 994203 | 85 | 75 | 77 |
| 孤 | B190207 | 994204 | 79 | 82 | 80.5 |
| 鹜 | B190208 | 994205 | 94 | 83.5 | 81.5 |
| 齐 | B190208 | 994206 | 80 | 69 | 68 |
| 飞 | B190208 | 994207 | 82 | 77 | 71 |
| 秋 | B190208 | 994208 | 77 | 57 | 58 |
| 水 | B190208 | 994209 | 91 | 88 | 86 |
| 共 | B190208 | 994210 | 96 | 89 | 90 |
| 长 | B190206 | 994211 | 70 | 45.5 | 50 |
| 天 | B190206 | 994212 | 74 | 65 | 66 |
| 一 | B190206 | 994213 | 81 | 71 | 76 |
| 色 | B190206 | 994214 | 83 | 75 | 77 |
| 乾 | B190206 | 994215 | 86 | 78 | 79 |
2、读取excel里面的数据存入到程序中,为了方便管理,以为excel建立了专门的对象,也为学生建立了专门的类。
3、根据读入的数数据,计算出每一位学生的加权成绩,再根据加权成绩确定该学生的等地是优秀还是别的。等地信息和加权成绩都保存在了学生类当中。
4、上方完成了数据的读入。对于程序来说所有的学生信息都已经可见了,我们根据班级、课程类型、等地等信息,计算出每个等地区间的人数和百分比占比。这个过程比较简单,遍历所有学生,比较是否符合筛选条件,如果符合,对应的统计人数就加一。
PYQT的QComboBox 控件为我们提供了一个非常不错的筛选条件选择机制。我们想知道选算条件的时候,只需要读取控件的文本就可以。python的文本机制极大的方便了我们的比较过程。

数据结构:
为excel对象、学生类、课程类、等地划分分别建立了对应的class,内容跟较多,具体在程序上体现的非常好了。拿学生类来举例:
class student: def __init__(self): self.id = ''#学号 self.name = ''#姓名 self.myclass=''#班级 self.lesson = [] # 存储课程成绩每一位学生有自己的学号、姓名、班级、和课程。因为每一位学生会有不止一门课程,这里就为课程开辟了一个列表,用来存放课程类对象。课程类对象的结构如下:
class lesson: def __init__(self): self.name_lesson = [] # 课程名称 self.grade_usual = 0 # 平时成绩 self.grade_mid = 0 # 期中成绩 self.grade_final = 0 # 期末成绩 self.grade_gene = 0 # 加权总成绩 self.rank = [] # 等地
def get_rank(self): global rank self.grade_gene = self.grade_usual * rank.weight_rank['平时'] + self.grade_mid * rank.weight_rank[ '期中'] + self.grade_final * rank.weight_rank['期末'] if rank.excellent_low <= self.grade_gene <= rank.excellent_high: self.rank = rank.excellent elif rank.good_low <= self.grade_gene < rank.good_high: self.rank = rank.good elif rank.medium_low <= self.grade_gene < rank.medium_high: self.rank = rank.medium elif rank.mypass_low <= self.grade_gene < rank.mypass_high: self.rank = rank.mypass elif rank.myfail_low <= self.grade_gene < rank.myfail_high: self.rank = rank.myfail每一个课程都有自己的课程名称、各种成绩等等。其中加权成绩、等地没法直接在本地读取需要调用get_rank方法来计算获取。
逻辑功能程序
main.py
import xlrdfrom class_student import *# PyQt5中使用的基本控件都在PyQt5.QtWidgets模块中from PyQt5.QtWidgets import QApplication, QMainWindow, QTableWidgetItem# 导入程序运行必须模块import sys# 导入designer工具生成的login模块from qus21 import Ui_MainWindowfrom PyQt5 import QtCorefrom functools import partialfrom qt_material import apply_stylesheet
class STUDENT_ALL: def __init__(self): self.num = 0 self.grade_all = [] # 每门课的平均分数 self.lesson_rank_rate = [] self.student_list = [] self.rate_excell = 0 self.rate_good = 0 self.rate_medium = 0 self.rate_mypass = 0 self.rate_myfail = 0
def student_init(self, excel): self.num = excel.sheets[0].rows # 获取学生数量 for student_ind in range(self.num): # 对学生的姓名,学号,班级初始化 student_temp = student() student_temp.name = excel.sheets[0].sheet.cell(student_ind, 0).value student_temp.myclass = excel.sheets[0].sheet.cell(student_ind, 1).value student_temp.id = excel.sheets[0].sheet.cell(student_ind, 2).value
# 导入课程成绩、等地 for lesson_ind in range(excel.sheet_num): lesson_temp = lesson() lesson_temp.name_lesson = excel.sheet_names[lesson_ind] lesson_temp.grade_usual = excel.sheets[lesson_ind].sheet.cell(student_ind, 3).value lesson_temp.grade_mid = excel.sheets[lesson_ind].sheet.cell(student_ind, 4).value lesson_temp.grade_final = excel.sheets[lesson_ind].sheet.cell(student_ind, 5).value
lesson_temp.get_rank() student_temp.lesson.append(lesson_temp)
self.student_list.append(student_temp) self.grade_all_init(excel) self.lesson_rank_init(excel)
# 生成每个科目的平均成绩 def grade_all_init(self, excel): for lesson_ind in range(excel.sheet_num): sum = 0 for student_ind in range(len(self.student_list)): sum = sum + self.student_list[student_ind].lesson[lesson_ind].grade_gene pass sum = sum / len(self.student_list) self.grade_all.append(sum)
def lesson_rank_init(self, excel): global rank for lesson_ind in range(excel.sheet_num): self.rate_excell = 0 self.rate_good = 0 self.rate_medium = 0 self.rate_mypass = 0 self.rate_myfail = 0 for student_ind in range(len(self.student_list)): rank_temp = self.student_list[student_ind].lesson[lesson_ind].rank if rank_temp == rank.excellent: self.rate_excell += 1 elif rank_temp == rank.good: self.rate_good += 1 elif rank_temp == rank.medium: self.rate_medium += 1 elif rank_temp == rank.mypass: self.rate_mypass += 1 else: self.rate_myfail += 1 lesson_rank_temp = lesson_rank() lesson_rank_temp.rate_excell = self.rate_excell / len(self.student_list) lesson_rank_temp.rate_good = self.rate_good / len(self.student_list) lesson_rank_temp.rate_medium = self.rate_medium / len(self.student_list) lesson_rank_temp.rate_mypass = self.rate_mypass / len(self.student_list) lesson_rank_temp.rate_myfail = self.rate_myfail / len(self.student_list) self.lesson_rank_rate.append(lesson_rank_temp)
class lesson_rank: def __init__(self): self.rate_excell = 0 self.rate_good = 0 self.rate_medium = 0 self.rate_mypass = 0 self.rate_myfail = 0
class EXCEL: # excel数据表对象 def __init__(self, wb): self.wb = wb # excel文件对象 self.sheet_num = wb.nsheets # sheet的数量 self.sheet_names = wb.sheet_names() # sheet的名字 self.sheets = [] # 初始化 self.get_sheets()
def get_sheets(self): for i in range(self.sheet_num): sheet_temp = SHEET() sheet_temp.sheet = self.wb.sheet_by_index(i) sheet_temp.name = self.sheet_names[i] sheet_temp.rows = self.wb.sheet_by_index(i).nrows sheet_temp.cols = self.wb.sheet_by_index(i).ncols self.sheets.append(sheet_temp)
class SHEET: # 表单对象 def __init__(self): self.sheet = [] # sheet的对象 self.name = [] # sheet的名字,方便调用 self.rows = 0 # sheet的列数 self.cols = 0 # sheet对象
rank = rank_def()excel = EXCEL(xlrd.open_workbook("成绩单.xlsx"))student_all = STUDENT_ALL()student_all.student_init(excel)
class MyMainForm(QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super(MyMainForm, self).__init__(parent) self.cursot = None self.setupUi(self) self.student_dis = [] self.pushButton.clicked.connect(partial(self.refresh))
def refresh(self): global student_all global excel global rank self.student_dis.clear() lesson_index = self.lesson.currentIndex() # 获取当前课程号 class_index = self.classroom.currentIndex() # 获取当前课程号 rank_index = self.rank.currentIndex() # 获取当前等地要求
for i in range(len(student_all.student_list)): # 筛选判断依据 if class_index == 0: class_wei = 1 else: class_wei = (student_all.student_list[i].myclass == self.classroom.currentText()) if rank_index == 0: rank_wei = 1 else: rank_wei = (student_all.student_list[i].lesson[lesson_index].rank == self.rank.currentText())
if (class_wei and rank_wei): self.student_dis.append(student_all.student_list[i])
print(len(self.student_dis)) self.display()
def display(self): self.table.clear() self.table.setRowCount(len(self.student_dis)) self.table.setColumnCount(8) self.table2.clear() self.table2.setRowCount(2) self.table2.setColumnCount(4) self.table2.setRowHeight(0, 50) # 显示成绩 headers = ['姓名', '班级', '学号', '平时成绩', '期中成绩', '期末成绩', '加权成绩', '等地'] self.table.setHorizontalHeaderLabels(headers); for student_ind in range(len(self.student_dis)): self.table.setItem(student_ind, 0, QTableWidgetItem(self.student_dis[student_ind].name)) # 姓名 self.table.setItem(student_ind, 1, QTableWidgetItem(self.student_dis[student_ind].myclass)) # 班级 self.table.setItem(student_ind, 2, QTableWidgetItem("%.0f" % self.student_dis[student_ind].id)) # 学号 self.table.setItem(student_ind, 3, QTableWidgetItem("%.2f" % self.student_dis[student_ind].lesson[ self.lesson.currentIndex()].grade_usual)) # 平时成绩 self.table.setItem(student_ind, 4, QTableWidgetItem("%.2f" % self.student_dis[student_ind].lesson[ self.lesson.currentIndex()].grade_mid)) # 期中成绩 self.table.setItem(student_ind, 5, QTableWidgetItem("%.2f" % self.student_dis[student_ind].lesson[ self.lesson.currentIndex()].grade_final)) # 期末成绩 self.table.setItem(student_ind, 6, QTableWidgetItem("%.2f" % self.student_dis[student_ind].lesson[ self.lesson.currentIndex()].grade_gene)) # 加权成绩 self.table.setItem(student_ind, 7, QTableWidgetItem( self.student_dis[student_ind].lesson[self.lesson.currentIndex()].rank)) # 等地
# 显示分数段占比 row = 0 self.table2.setItem(row, 0, QTableWidgetItem("优秀人数(率):")) self.table2.setItem(row, 1, QTableWidgetItem("良好人数(率):")) self.table2.setItem(row, 2, QTableWidgetItem("中等人数(率):")) self.table2.setItem(row, 3, QTableWidgetItem("及格人数(率):")) self.table2.setItem(row, 4, QTableWidgetItem("不及格人数(率):"))
self.table2.setItem(row + 1, 0, QTableWidgetItem("%d(%.2f%%)" % (student_all.rate_excell, student_all.lesson_rank_rate[ self.lesson.currentIndex()].rate_excell * 100))) self.table2.setItem(row + 1, 1, QTableWidgetItem("%d(%.2f%%)" % (student_all.rate_good, student_all.lesson_rank_rate[ self.lesson.currentIndex()].rate_good * 100))) self.table2.setItem(row + 1, 2, QTableWidgetItem("%d(%.2f%%)" % (student_all.rate_medium, student_all.lesson_rank_rate[ self.lesson.currentIndex()].rate_medium * 100))) self.table2.setItem(row + 1, 3, QTableWidgetItem("%d(%.2f%%)" % (student_all.rate_mypass, student_all.lesson_rank_rate[ self.lesson.currentIndex()].rate_mypass * 100))) self.table2.setItem(row + 1, 4, QTableWidgetItem("%d(%.2f%%)" % (student_all.rate_myfail, student_all.lesson_rank_rate[ self.lesson.currentIndex()].rate_myfail * 100)))
if __name__ == '__main__': QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling) # 解决页面显示不一致的问题
app = QApplication(sys.argv)
myWin = MyMainForm() apply_stylesheet(app, theme='dark_red.xml') myWin.show()
sys.exit(app.exec_())class_student.py
class student: def __init__(self): self.id = ''#学号 self.name = ''#姓名 self.myclass=''#班级 self.lesson = [] # 存储课程成绩
class lesson: def __init__(self): self.name_lesson = [] # 课程名称 self.grade_usual = 0 # 平时成绩 self.grade_mid = 0 # 期中成绩 self.grade_final = 0 # 期末成绩 self.grade_gene = 0 # 加权总成绩 self.rank = [] # 等地
def get_rank(self): global rank self.grade_gene = self.grade_usual * rank.weight_rank['平时'] + self.grade_mid * rank.weight_rank[ '期中'] + self.grade_final * rank.weight_rank['期末'] if rank.excellent_low <= self.grade_gene <= rank.excellent_high: self.rank = rank.excellent elif rank.good_low <= self.grade_gene < rank.good_high: self.rank = rank.good elif rank.medium_low <= self.grade_gene < rank.medium_high: self.rank = rank.medium elif rank.mypass_low <= self.grade_gene < rank.mypass_high: self.rank = rank.mypass elif rank.myfail_low <= self.grade_gene < rank.myfail_high: self.rank = rank.myfail
class rank_def: # 用来计算加权分数和评定等地的常量 def __init__(self): # 等地划分依据 self.excellent_low = 90 self.excellent_high = 100 self.good_low = 80 self.good_high = 90 self.medium_low = 70 self.medium_high = 80 self.mypass_low = 60 self.mypass_high = 70 self.myfail_low = 0 self.myfail_high = 60
# 等地名称 self.excellent = '优' self.good = '良' self.medium = '中' self.mypass = '及格' self.myfail = '不及格'
# 成绩加权比例 self.weight_rank = {'平时': 0.3, '期中': 0.3, '期末': 0.4}
rank = rank_def()结果及完善方向



完善方向:
每个等地区间内的人数和比例可以根据筛选条件进行变动。
模拟电信计费系统的设计与实现(B2)
设计题目及要求
设计一个模拟电信计费系统。能实现从文件中读取通话以及费率资料,并提供计费、话费查询和话单查询等服务。通过此课题,熟练掌握文件读写、数组、结构体、格式输入输出的各种操作,以及友好界面的设计和一些算法思想的应用。
(1) 计费功能。根据存放在源数据文件中的通话记录和长途费率文件对每一条通话记录计算其通话费用,并将结果保存在费用文件中。其中:
通话费的计算方法如下:
通话费=长途电话费+本地电话费
长途电话费=费率(元/分钟)×通话时长(分钟)
(通话时长不满1分钟的按1分钟计算)
本地电话费为:3分钟以内0.3元,以后每1分钟递增0.2元。
(2) 话费查询。输入一个电话号码,从费用文件中统计该电话号码的所有本地话费、长途话费,并从用户文件中查找其用户名,最后在屏幕上显示:
用户名 电话号码 本地话费 长途话费 话费总计
(3) 话单查询。输入一个电话号码,查询并在屏幕显示该用户的所有通话记录,格式为:
用户名 主叫电话号码 被叫电话号码 通话时长
设计思想及程序流程框图
UI:

数据管理:
1.本系统的输入输出文件
本系统的输入文件为一个excel文件,内部含有三个sheet表单存放着如下3类信息:
(1) 源数据文件
存放:主叫区号 主叫电话号码 被叫区号 被叫电话号码 通话时长(秒)
每次通话作为一条记录,占源数据文件的一行。
每条记录中各数据之间以空格间隔,例如:025 3491234 010 62320983 90
每个电话号码可以有多次通话记录。
如果主、被叫区号相同,则通话记录为本地通话记录;否则为长途通话记录。
(2) 长话费率文件
存放:区号 费率
例如:010 1.20 表示从本地打往区号为010的地区每分钟收费1.20元。
(3) 用户文件
存放: 电话号码 用户姓名
例如: 3491234 张明
本系统的输出是在excel里面建立一个“费用”的表单:
费用文件
存放:主叫电话号码 通话类型 话费金额
其中,通话类型表示本次通话是长途还是本地。
hd—共有20条通话记录,分别是:
| 主叫区号 | 主叫电话 | 被叫区号 | 被叫电话 | 通话时长(s) |
|---|---|---|---|---|
| 25 | 3491234 | 25 | 5319971 | 70 |
| 25 | 4927038 | 10 | 62110045 | 236 |
| 25 | 7216340 | 25 | 4521009 | 310 |
| 25 | 3491234 | 571 | 2199516 | 100 |
| 25 | 8120321 | 21 | 81094532 | 50 |
| 25 | 3491234 | 25 | 5319971 | 80 |
| 25 | 4927038 | 25 | 3491234 | 115 |
| 25 | 8120321 | 25 | 7216340 | 47 |
| 25 | 7216340 | 10 | 62110045 | 93 |
| 25 | 3491234 | 10 | 62110045 | 792 |
| 25 | 4927038 | 571 | 2199516 | 931 |
| 25 | 3491234 | 25 | 5319971 | 580 |
| 25 | 4927038 | 25 | 3491234 | 358 |
| 25 | 8120321 | 21 | 81094532 | 197 |
| 25 | 7216340 | 25 | 4521009 | 256 |
| 25 | 7216340 | 10 | 62110045 | 193 |
| 25 | 3492200 | 25 | 4521009 | 320 |
| 25 | 3491234 | 25 | 5319971 | 270 |
fl 有4条记录
| 区号 | 费率 |
|---|---|
| 10 | 1.2 |
| 20 | 1.2 |
| 21 | 0.8 |
| 571 | 1 |
yh 有5条记录
| 电话 | 姓名 |
|---|---|
| 3491234 | 张明 |
| 4927038 | 李小红 |
| 7216340 | 王励 |
| 3492200 | 赵强 |
| 8120321 | 杨冬 |
程序实现:
为每个功能编写一个自定义的函数。自定义一个函数,读取实现存好的文件,输出结果实现源数据文件。同理编写显示其余两个文件的函数。然后自定义函数按比例计算每个学生的总评成绩,已经对应的等级,并且打印,完成要求3。话费计算和话单显示这两个功能,也需要自定义函数实现。话费计算需要调用源数据文件、费率文件以及用户文件,判断出每条记录的费用累加到对应的用户,储备好,用来后面输出。而话单显示功能需要调用源数据文件和用户文件,仍然使用遍历的方法,将号码与每一个记录进行匹配,匹配则输出,不匹配则忽略。最后使用结束,弹出结束界面。

逻辑功能程序
main.py
from myclass import *import xlrd # 引入库import mathimport openpyxl# PyQt5中使用的基本控件都在PyQt5.QtWidgets模块中from PyQt5.QtWidgets import QApplication, QMainWindow, QTableWidgetItem# 导入程序运行必须模块import sys# 导入designer工具生成的login模块from qus22 import Ui_MainWindowfrom PyQt5 import QtCorefrom functools import partialfrom qt_material import apply_stylesheet
excel = EXCEL(xlrd.open_workbook("通话.xlsx"))
hd = []fl = []yh = []fy = []dic = dict() # 创建一个空字典,用来通过电话快速访问用户名
hf_dis = []hd_dis = []
def dict_init(): for i in range(len(yh)): dic[yh[i].tele_user] = yh[i].name
# 设置用于展示的hf_dis,hd_disdef inf_dis_init(): global hd global fl global yh global fy for i in range(len(yh)): hf_dis_tem = hf_dis_class() hf_dis_tem.name = yh[i].name hf_dis_tem.tele = yh[i].tele_user hf_dis_tem.money_local = 0 hf_dis_tem.money_far = 0 for j in range(len(fy)): if fy[j].tele == hf_dis_tem.tele: if fy[j].call_type == '本地': hf_dis_tem.money_local += fy[j].money else: hf_dis_tem.money_far += fy[j].money hf_dis_tem.money_total = hf_dis_tem.money_local + hf_dis_tem.money_far hf_dis.append(hf_dis_tem)
for i in range(len(hd)): hd_dis_tem = hd_dis_class() hd_dis_tem.tele_m = hd[i].tele_m hd_dis_tem.tele_s = hd[i].tele_s hd_dis_tem.time = hd[i].time hd_dis_tem.name = dic[hd[i].tele_m] hd_dis.append(hd_dis_tem)
# 初始化各个数据信息def init_hfyf(): global hd global fl global yh global fy global excel for i in range(excel.sheets[0].rows): hd_tem = hd_class() hd_tem.region_m = excel.sheets[0].sheet.cell(i, 0).value hd_tem.tele_m = excel.sheets[0].sheet.cell(i, 1).value hd_tem.region_s = excel.sheets[0].sheet.cell(i, 2).value hd_tem.tele_s = excel.sheets[0].sheet.cell(i, 3).value hd_tem.time = excel.sheets[0].sheet.cell(i, 4).value hd.append(hd_tem)
for i in range(excel.sheets[1].rows): fl_tem = fl_class() fl_tem.region = excel.sheets[1].sheet.cell(i, 0).value fl_tem.rate = excel.sheets[1].sheet.cell(i, 1).value fl.append(fl_tem)
for i in range(excel.sheets[2].rows): yh_tem = yh_class() yh_tem.tele_user = excel.sheets[2].sheet.cell(i, 0).value yh_tem.name = excel.sheets[2].sheet.cell(i, 1).value yh.append(yh_tem)
# 对每一条费用进行初始化 for i in range(len(hd)): fy_temp = fy_class() fy_temp.tele = hd[i].tele_m
if hd[i].region_m == hd[i].region_s: # 同区域通话 fy_temp.call_type = '本地' time = math.ceil(hd[i].time / 60) if time <= 3: fy_temp.money = 0.5 else: time2 = math.ceil((time - 3) / 3) # 向上取整算是超过了几个3min fy_temp.money = 0.5 + time2 * 0.2 else: fy_temp.call_type = '长途' time = math.ceil(hd[i].time / 60) # 计算本地通话金额 if time <= 3: money1 = 0.5 else: time2 = math.ceil((time - 3) / 3) # 向上取整算是超过了几个3min money1 = 0.5 + time2 * 0.2 # 计算长途通话金额 fl_rate = 0 for j in range(len(fl)): if fl[j].region == hd[i].region_s: fl_rate = fl[j].rate break money2 = time * fl_rate fy_temp.money = money1 + money2 fy.append(fy_temp)
for i in range(len(fy)): excel_tem = openpyxl.load_workbook("通话.xlsx") sheet_tem = excel_tem['费用文件'] sheet_tem.cell(i + 1, 1).value = fy[i].tele sheet_tem.cell(i + 1, 2).value = fy[i].call_type sheet_tem.cell(i + 1, 3).value = fy[i].money excel_tem.save('通话.xlsx') dict_init() inf_dis_init()
class MyMainForm(QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super(MyMainForm, self).__init__(parent) self.cursot = None self.setupUi(self) self.mode = 0 # 0为话费查询,1为话单查询 self.button.clicked.connect(partial(self.refresh))
def refresh(self): self.mode = self.comboBox.currentIndex() self.tableWidget.clear()
# 话费查询 if self.mode == 0: tele_tar = int(self.lineEdit.text()) # 目标电话 # print(self.lineEdit.text()) self.tableWidget.setColumnCount(5) # 控制表格有几列 self.tableWidget.setRowCount(1) # 控制表格有几行 headers = ['姓名', '电话', '本地话费', '长途话费', '总话费'] self.tableWidget.setHorizontalHeaderLabels(headers) # 设置表头 for i in range(len(hf_dis)): if hf_dis[i].tele == tele_tar: self.tableWidget.setItem(0, 0, QTableWidgetItem(hf_dis[i].name)) self.tableWidget.setItem(0, 1, QTableWidgetItem("%d" % hf_dis[i].tele)) self.tableWidget.setItem(0, 2, QTableWidgetItem("%.2f" % hf_dis[i].money_local)) self.tableWidget.setItem(0, 3, QTableWidgetItem("%.2f" % hf_dis[i].money_far)) self.tableWidget.setItem(0, 4, QTableWidgetItem("%.2f" % hf_dis[i].money_total)) break elif self.mode == 1: tele_tar = int(self.lineEdit.text()) # 目标电话 lis_dis = [] for i in range(len(hd_dis)): if hd_dis[i].tele_m == tele_tar: lis_dis.append(hd_dis[i]) self.tableWidget.setColumnCount(4) # 控制表格有几列 self.tableWidget.setRowCount(len(lis_dis)) # 控制表格有几行 headers = ['姓名', '主叫电话', '被叫电话', '通话时长'] self.tableWidget.setHorizontalHeaderLabels(headers) # 设置表头 for i in range(len(lis_dis)): self.tableWidget.setItem(i, 0, QTableWidgetItem(lis_dis[i].name)) self.tableWidget.setItem(i, 1, QTableWidgetItem("%d" % lis_dis[i].tele_m)) self.tableWidget.setItem(i, 2, QTableWidgetItem("%d" % lis_dis[i].tele_s)) self.tableWidget.setItem(i, 3, QTableWidgetItem("%d秒" % lis_dis[i].time)) else: self.tableWidget.setColumnCount(3) # 控制表格有几列 self.tableWidget.setRowCount(len(fy)) # 控制表格有几行 headers = ['主叫电话', '通话类型', '话费'] self.tableWidget.setHorizontalHeaderLabels(headers) # 设置表头 for i in range(len(fy)): self.tableWidget.setItem(i, 0, QTableWidgetItem("%d" % fy[i].tele)) self.tableWidget.setItem(i, 1, QTableWidgetItem(fy[i].call_type)) self.tableWidget.setItem(i, 2, QTableWidgetItem("%.2f" % fy[i].money))
if __name__ == '__main__': init_hfyf() QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling) # 解决页面显示不一致的问题
app = QApplication(sys.argv)
myWin = MyMainForm() apply_stylesheet(app, theme='dark_red.xml') myWin.show()
sys.exit(app.exec_())myclass.py
class hd_class: def __init__(self): self.region_m = 0 # 主叫区号 self.tele_m = 0 # 主叫电话 self.region_s = 0 # 被叫区号 self.tele_s = 0 # 被叫电话 self.time = 0 # 通话时间,单位秒
class fl_class: def __init__(self): self.region = 0 # 区号 self.rate = 0 # 费率
class yh_class: def __init__(self): self.tele_user = 0 # 用户电话 self.name = 0 # 用户姓名
class fy_class: def __init__(self): self.tele = 0 # 主叫电话 self.call_type = 0 # 通话类型:本地还是长途 self.money = 0 # 话费
class hf_dis_class: def __init__(self): self.name = 0 # 用户姓名 self.tele = 0 # 电话 self.money_local = 0 # 本地话费 self.money_far = 0 # 长途话费 self.money_total = 0 # 总话费
class hd_dis_class: def __init__(self): self.name = 0 # 用户姓名 self.tele_m = 0 # 主叫电话 self.tele_s = 0 # 被叫电话 self.time = 0 # 通话时长,单位秒
class EXCEL: # excel数据表对象 def __init__(self, wb): self.wb = wb # excel文件对象 self.sheet_num = wb.nsheets # sheet的数量 self.sheet_names = wb.sheet_names() # sheet的名字 self.sheets = [] self.get_sheets()
def get_sheets(self): for i in range(self.sheet_num): sheet_temp = SHEET() sheet_temp.sheet = self.wb.sheet_by_index(i) sheet_temp.name = self.sheet_names[i] sheet_temp.rows = self.wb.sheet_by_index(i).nrows sheet_temp.cols = self.wb.sheet_by_index(i).ncols self.sheets.append(sheet_temp)
def excel_open(self, wb): self.wb = wb # excel文件对象
class SHEET: # 表单对象 def __init__(self): self.sheet = [] # sheet的对象 self.name = [] # sheet的名字,方便调用 self.rows = 0 # sheet的列数 self.cols = 0 # sheet对象结果及完善方向
计费查看:

话费查询:

话单查询:

部分信息可能已经过时