基于C++实现(CS界面)家谱管理系统

⼀、需求分析

《家谱管理系统》程序的设计⽬的,是为了解决中国传统家谱不易保存、不易修改、不易统计的缺陷。利⽤计算机程序,可以实现在计算机上存储、管理、查看家谱的相关信息。

⽬标功能:

  1. 建⽴家谱:在计算机上建⽴树状家谱结构。要求⽤户友好,便于不懂计算机的⼈使⽤, 因此需要制作图形⽤户界⾯、⽀持⿏标操作,操作逻辑与市⾯常规操作系统⼀致。
  2. 管理信息:⽅便对家谱成员进⾏信息管理。其中要求实现家谱成员的信息修改、成员的 插⼊与删除,信息要求包括⼀个成员的基本信息,包括:姓名、性别、出⽣⽇期、死亡⽇期、出⽣地点、身⾼等。要求⽀持⿏标操作,操作逻辑简单、与市⾯常规操作系统⼀致。
  3. 统计信息:为了满⾜对⼀整个家族的研究,系统要求⽀持对家谱中所有成员信息进⾏统 计,包括对医学研究有价值的信息,如:年龄、身⾼等。要求实现⿏标操作,操作逻辑简单、与市⾯常规操作系统⼀致。
  4. 存储信息:家谱管理要求实现信息存储,⽅便信息的重复查看、使⽤。要求包括的功能 有:打开程序⾃动进⾏信息的初始化,将计算机内存储的数据⾃动初始化为家谱数据;完成信息的修改后可以实现保存,将家谱信息保存⾄计算机。

⼆、项⽬设计

1.总体设计:

项⽬的头⽂件、源⽂件及ui⽂件

在家谱管理系统项⽬中,我们创建了四个ui界⾯、六个头⽂件及七个源⽂件。

其中四个ui界⾯分别⽤于录⼊信息、主窗体的显示、统计值信息的显示、依据输⼊姓名搜索⽬标信息。

头⽂件中:

mainwindow.h 中声明 MainWindow类 ,包括将Item的相关信息输出到MainWindow.ui中相应标签中、点击搜索/统计按钮,弹出相应窗⼝、进⾏搜索等;相关函数与信号和槽的连接 在 mainwindow.cpp 中实现;

information.h 中声明 Information类 ,包括录⼊的相关信息,信息的返回等;相关函数在 information.cpp 中实现;

mytreewidget.h 中声明了 MyT reeWidget类,包括:点击按钮显示结点的信息、新建结点、删除结点、对结点进⾏信息的修改、重命名结点等功能函数的声明;相关函数与信号和槽的连接在 mytreewidget.cpp 中实现;

mytreewidgetitem.h 中声明了 MyT reeWidget Item类,包括修改结点信息的函数声明; 相关函数在 mytreewidgetitem.cpp 中实现;

result.h 中声明了 Result类,其中有全部结点的信息的统计值,如总结点数、平均年龄、平均身⾼,并声明了输出统计值的函数;相关函数与信号和槽的连接在 result.cpp、mytreewidget.cpp 中实现;

search.h 中声明了 Search类,包括依据输⼊的姓名进⾏搜索的函数声明,和搜索结点信息输出函数的声明;相关函数与信号和槽的连接在 search.cpp 、mytreewidget.cpp 中实现。

main.cpp 中的main函数作为程序的起点,运⾏程序。

项⽬设计的类图

2.算法设计与分析:

查找算法的流程图

查找算法的代码部分

根据⼈名进⾏查找时,我们点击主窗⼝的查找按钮,在输⼊⼀个⼈名后,点击查找的按钮,进⾏查找。

查找的原理是利⽤for循环依次访问根结点,取结点的⼈名信息,与输⼊的⼈名进⾏⽐ 对,如果相等,则找到了⽬标结点,返回此结点。

如果在根结点中没找到,就依次遍历根结点的⼦结点,先获得当前结点的⼦结点个数,⽤for循环访问各个⼦代,如果找到了⽬标结点,返回此结点,否则就对此函数进⾏递归调⽤, 这样可以在找到⽬标结点前⼀直遍历,当遍历所有结点完我们仍没有找到⽬标结点,则说明树中没有此⼈。

如果找到此⼈,会输出他的⽗亲和孩⼦,同时输出他的个⼈信息;未找到此⼈,输出“未 找到此⼈”。

统计算法的流程图

统计算法的代码部分

根据树的数据统计时,我们点击主窗⼝中的统计按钮,在统计界⾯中,点击统计数据的按钮,进⾏数据的统计与输出,统计的数据有家谱中总⼈数、平均年龄、平均身⾼。

数据统计的原理是⽤for循环依次访问树中的结点,⾸先遍历每个根结点,每访问⼀个结 点,对num进⾏加1、对sum_age进⾏累加、对sum_height进⾏累加。

依次遍历⼦结点,先获得当前结点的⼦结点个数,⽤for循环访问各个⼦代,对各个数据 进⾏累加,再对⼦结点递归调⽤此函数,这样可以遍历所有除根结点之外的结点数据,和最初对根结点的数据⼀起组成了累计的数据。

再对数据进⾏处理,求均值,输出到相应的ui的label上。

  1. ⽤到的数据结构:

项⽬中⽤到了树形结构,⼀个结点可以和多个结点相连,Qt中的QT reeWidget运⽤的就是树形结构对数据进⾏存储,我们在项⽬中对树中结点进⾏遍历,⽤到的是深度优先的遍历⽅式,其形式是递归。

利⽤树形结构,能把家谱中⽗⼦关系表达得很清晰,利⽤深度优先的遍历⽅式使遍历有逻辑地进⾏,使结点能按顺序地进⾏搜索。

三、测试报告

3.1合法数据测试

3.1.1合法祖先结点的建⽴:

3.1.2合法⼦代结点的建⽴:

3.1.3合法结点数据查询:

3.1.4合法数据统计:

3.2⾮法数据测试

3.2.1⾮法信息修改(性别、年龄、身⾼):

3.2.2⽆效成员查询

3.3功能展示

3.3.1祖先结点创建与删除

在空⽩区域单击⿏标右键,弹出选项

3.3.2⼦代结点创建与删除

选中结点单击⿏标右键,弹出选项

3.3.4成员信息查询

点击右下⽅”查询“按钮

3.3.5家谱成员数据统计

四、设计过程中遇到的问题及解决⽅法

问题⼀:图形⽤户界⾯的制作。

解决⽅法:我们⼩组之前并没有图形⽤户界⾯的开发经验,在接到这个⼤作业后,我们先是在⽹络上查找了有关图形⽤户界⾯的制作⼯具,了解到Qt功能强⼤、跨平台性能好的特点 后,我们即选⽤了Qt作为我们的开发⼯具。并且在本学期通过⽹络课程+⽹络⽂档+图书的⽅ 式,初步学习了Qt开发的基本过程和主要功能,并在此基础上使⽤Qt完成了本次⼤作业。

问题⼆:Qt中树对象内部每个结点信息的存储。

解决⽅法:在创建每个成员信息作为结点时,发现把成员信息存储到Qt原有的-- QT reeWidget Item类中较为复杂,因此必须继承该类,派⽣⼀个包含成员信息的新的类-- MyT reeWidget Item。但是在派⽣过程中,由于对C++继承与派⽣机制掌握的不扎实,⾃⼰没有注意到很多之前使⽤的QT reeWidget对象中对QT reeWidget Item的函数将不再适⽤于⾃⼰派⽣的对象。后来在⽹络上查询后了解到,编译器在编译时,会建⽴⼀个类的索引表,根据指针类型来确定指针指向对象成员的偏移量,所以对⽗类对象使⽤派⽣类对象指针不⽤进⾏类型转换,但是对派⽣类对象使⽤⽗类对象指针必须进⾏强制类型转换。

问题三:Qt树组件中遍历、查找的算法设计。

解决⽅法:Qt中树结构是封装成类的,⽆法直接通过指针获得⽗类或者⼦类结点,通过 查询Qt的官⽅⽂档,找到了QT reeWidget和QT reeWidget Item封装好的函数parent( )和child( )来返回⽗⼦结点的指针,以及childcount( )返回孩⼦结点个数。有了这些函数,就可以通过递归⼦树来实现遍历、查找功能。

五、尚未解决的问题及考虑应对的策略

本程序在设计计算机存储功能时遇到了困难。⽬标是⽤户在点击保存功能按钮时,将每个成员的信息输出⾄⽬标计算机硬盘⽬录上的⽂本⽂档中;⽽⽤户在重新打开此程序时,程序会计算机存储功能⾃动读取⽬标计算机硬盘⽬录上的⽂本⽂档,实现通过⽂本⽂档数据初始化成员信息,从⽽实现程序的重复多次使⽤。

在实际编写程序时,发现对于此类⾮⼆叉树的更⼀般的树结构,不太容易通过较为简单的⽅式实现相同类型、规格数据初始化⼀棵树。在向⼀些同学请教、上⽹查找⽅法之后,我们还是没能够在有限的时间⾥完成这个很重要的功能,但是也有了⼀些想法。初步定下来的未来实现思路有两种。

思路⼀、使⽤”索引“

常规的通过数列初始化⼆叉树的⽅法对于家谱这种”多叉树“已经不适⽤,为此我们想到可 以在数据存储时,为每个成员添加⼀个”索引“。可以在索引中标注其孩⼦结点的名字,在初始 化此家谱时,初始化完成⽗亲结点后,通过索引找到孩⼦结点;建⽴好孩⼦结点后,通过孩⼦ 结点的索引继续查找孩⼦结点的孩⼦……通过递归⽅法,按照深度优先的⽅向建⽴树结构。

但是这种⽅法运⾏所消耗的时间可能会⽐较多,读取⽂件操作本来就是⽐较耗时的指令, 遍历⽂件的次数⼜很多,在数量⼤的情况下,可能会花费较多时间。

思路⼆、使⽤数据库

在⽹络上查找相关的内容时,我们发现CSDN上有⼀名作者初始化树状结构时使⽤了数据 库,通过数据库提供的丰富功能,⽅便地实现了数据的保存和树的初始化。但是我们⼩组两⼈都没有数据库操作知识作为基础,最后剩下的⾃学时间也不太够⽤。

没能完成如此重要的功能,我们的程序就只能算⼀个半成品,我们两个⼈都很不⽢⼼。我们⼩组希望在寒假的时候,再花费⼀点时间将数据保存和初始化功能完善好,使该程序成为⼀个完整可⽤的家谱管理系统。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

神仙别闹

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值