课程设计---族谱管理系统(c++)

这篇具有很好参考价值的文章主要介绍了课程设计---族谱管理系统(c++)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

系统简介

课设题目

界面展示

代码实现

Node.h

TreeNode.h

Genealogy.h

Genealogy.cpp

button.h

主函数

Genghis Khan.txt

图片文件

测试案例

结语


系统简介

族谱管理系统是数据结构课程的一个经典的课程设计案例,主要考查对大家对树结构的掌握与运用。以下是我在课程设计时所写的代码,希望能够对大家起到借鉴作用。

课设题目

课程管理系统

【基本功能】

(1)初始化系统:读取族谱数据文件(txt文件),建立初始族谱。族谱数据文件预先手工建立。

(2)显示族谱:输出族谱

(3)添加成员:提示输入成员信息,在族谱中添加成员。

(4)修改成员:提示输入成员信息,修改成员信息。

(5)删除成员:提示输入成员信息,从族谱中删除成员。

(6)查询:根据指定条件查询数据并输出。

(7)保存:保存当前族谱数据到文件(txt文件)。

(8)退出:退出系统。

【基本功能说明】

(1)成员基本信息:姓名,生年,卒年。

(2)显示族谱:输出成员姓名,注意可读性。

(3)添加、修改成员:注意长幼有序的问题。

(4)查询:提供按姓名查询、按“代”查询、查询孩子、查询父亲、查询兄弟等五种方式,输出结果注意可读性。

(5)铁木真族谱数据文件:Genghis Khan.txt(放在文末)

界面展示

对于界面的选择,我使用的是easyX设计的界面。由控制台与鼠标相结合完成所有功能。

以下是部分界面展示:

族谱管理系统,课程设计,c++,数据结构

族谱管理系统,课程设计,c++,数据结构

族谱管理系统,课程设计,c++,数据结构族谱管理系统,课程设计,c++,数据结构

代码实现

代码整体为模板类的形式。

Node.h

定义每一个结点中包含的数据

//Node.h
#pragma once
#include <string>
using namespace std;
struct Node
{
	string name; //名字
	int birthyear;//生年
	int deathyear;//卒年
	int generation;//代
	Node()
	{
		birthyear = 0;
		deathyear = 0;
		generation = 0;
	};
	Node(string n, int birth, int death, int g)
	{
		name = n;
		birthyear = birth;
		deathyear = death;
		generation = g;
	};
	Node(string n, int birth, int death)
	{
		name = n;
		birthyear = birth;
		deathyear = death;
		generation = 0;
	};
};

TreeNode.h

定义树的结点,采用孩子兄弟父亲三个指针的三叉链表类型。

//TreeNode.h
#pragma once
#include"Node.h"
template <class ElemType>
struct TreeNode
{
	ElemType data;
	TreeNode* brother;//用来指向兄弟
	TreeNode* child;//用来指向孩子
	TreeNode* parent;//用来指向父亲
	TreeNode()
	{
		brother = child = parent = NULL;
	}
	TreeNode(Node d,TreeNode* b,TreeNode* c, TreeNode* p)
	{
		data = d;		// 数据元素值
		brother = b;	// 兄弟
		child = c;	// 孩子
		parent = p; //父亲
	}
};

Genealogy.h

完成系统所要用到的所有函数的定义

//Genealogy.h
#pragma once
#include<fstream>
#include"TreeNode.h"
#include"Node.h"
#include"button.h"
#include<iostream>
using namespace std;
template <class ElemType>
class Genealogy
{
private:
	TreeNode<ElemType>* root;//根节点,存放第一代族长
	int g;//第几代
	int i = 1;
	int y = 20;
	int x = 400;
public:
	Genealogy() {
		root = NULL;
		g = 0;
	};
	Genealogy(TreeNode<ElemType>* r, int ge) {
		root = r;
		g = ge;
	};
	void InitTree(fstream& file);//初始化族谱
	TreeNode<ElemType>* children(TreeNode<ElemType>* r, string n, int b, int d, int g);//添加一个节点信息
	bool Addperson(string n, int b, int d, string f);//添加成员
	TreeNode<ElemType>* search(TreeNode<ElemType>* r, string n);//在族谱查找成员
	int generation(TreeNode<ElemType>* p);//返回某成员是第几代
	bool Change(string n, Node newname);//修改成员信息
	bool Delete(string n);//删除成员信息
	void Savefile(TreeNode<ElemType>* r,fstream& file);//保存成员信息
	void searchgeneration(TreeNode<ElemType>* p, int g, int k);//查询某一代的成员
	bool searchchildren(string n,int y);//查询某人的孩子
	bool searchparent(string n);//查询某人的父亲
	void searchbrother(string n,int y);//查询某人的兄弟
	void Showmessage(int y, string n, int b, int d, string f);//展示成员信息,只能控制表格位置
	void Showmessage(int y, int h, string n, int b, int d, string f);//展示成员信息,控制表格位置及表格高度
	void Showtitle();//展示表格表头
	void Showtitle(int y);//展示表格表头,并能控制表头位置
	void Coutallmessage(TreeNode<ElemType>* r,int k) ;//展示族谱
	TreeNode<ElemType>* getroot() {
		return root;//返回根节点
	};
	void Coutname(TreeNode<ElemType>* p) {
		cout << p->data.name;//输出节点所存信息的名字
	};
	void Showname(TreeNode<ElemType>* p,int x,int y)//在目标位置展示节点所存信息的名字
	{
		//line(x - 25, y + 15, x, y + 15);
		button b;
		b.build(x,y,100,25,YELLOW,p->data.name.data());
		b.drawbutton();
	};
};

Genealogy.cpp

函数方法的实现

//Genealogy.cpp
#include "Genealogy.h"
#include<iostream>
using namespace std;
template <class ElemType>
void Genealogy<ElemType>::InitTree(fstream& file)
{
	if (file.eof())//若已到文件末尾,则结束进程
	{
		return;
	}
	string name;
	file >> name;
	int birth, death;
	file >> birth >> death;
	g = 1;//代
	root = children(root, name, birth, death, g);//先将第一代族长存到根节点
	string fathername;
	while (!file.eof())
	{
		file >> name >> birth >> death >> fathername;
		Addperson(name, birth, death, fathername);//将文件内所有信息依次存入树中
	}
}

template <class ElemType>
TreeNode<ElemType>* Genealogy<ElemType>::children(TreeNode<ElemType>* r, string n, int b, int d, int g)
{
	r = new TreeNode<ElemType>();
	r->data.name = n;
	r->data.birthyear = b;
	r->data.deathyear = d;
	r->data.generation = g;
	//cout << n << b << d << g << endl;
	return r;
}

template <class ElemType>
bool Genealogy<ElemType>::Addperson(string n, int b, int d, string f)
{
	TreeNode<ElemType>* p, * q;
	p = search(root, f);//存放父亲节点
	q = p;
	g = generation(p);//获取父亲是第几代
	if (p == NULL) //判断是否有重名
	{
		settextcolor(RGB(254, 67, 101));//设置字体颜色
		settextstyle(200, 0, "楷体");//设置字体属性,宽度35,高度0(自适应),字体楷体
		outtextxy(300, 300, "父亲不在家谱内!");
		cout << "父亲不在家谱内" << endl;
		return false;//添加失败,返回false
	}
	if (p->child == NULL)//孩子信息添加,当满足该父辈无子女时,进入条件判断
	{
		g++;//孩子比父亲大一代
		if (search(root, n) != NULL)//若添加之人已存在
		{
			settextcolor(RGB(254, 67, 101));//设置字体颜色
			settextstyle(200, 0, "楷体");//设置字体属性,宽度35,高度0(自适应),字体楷体
			outtextxy(300, 300, "添加失败!");
			settextstyle(100, 0, "楷体");//设置字体属性,宽度35,高度0(自适应),字体楷体
			outtextxy(300, 500, "族谱中已有此人。");
			cout << "添加失败";
			return false;//添加失败,返回false
		}
		else
		{
			p->child = children(p->child, n, b, d, g);//将孩子信息存入父亲的孩子节点
			p->child->parent = p;//将孩子的父亲指针指向父亲节点
			p->child->brother = NULL;
			p->child->child = NULL;
		}
	}
	else//当该父辈之前已经有子女的时候,则此新添加的成员为添加的前一个孩子的兄弟
	{
		p = p->child;
		g++;//孩子比父亲大一代
		if (search(root, n) != NULL)若添加之人已存在
		{
			settextcolor(RGB(254, 67, 101));//设置字体颜色
			settextstyle(200, 0, "楷体");//设置字体属性,宽度35,高度0(自适应),字体楷体
			outtextxy(300, 300, "添加失败!");
			settextstyle(100, 0, "楷体");//设置字体属性,宽度35,高度0(自适应),字体楷体
			outtextxy(300, 500, "族谱中已有此人。");
			cout << "添加失败";
			return false;//添加失败,返回false
		}
		else
		{
			/*
			while ( p->brother != NULL) //未进行长幼有序排列
			{
				p = p->brother;
			}
			p->brother=children(p, n, b, d, g);
			p->brother->parent = q;
			p->brother->brother = NULL;
			p->brother->child = NULL;*/
			TreeNode<ElemType>* q = new TreeNode<ElemType>();
			q = children(q, n, b, d, g);
			if (b < p->data.birthyear)//若添加之人的生年比第一个孩子小
			{
				q->brother = p;
				p->parent->child = q;
			}
			else//未添加到第一个
			{
				while (p->brother != NULL && b > p->brother->data.birthyear)//找到添加之人在兄弟中的位置
				{
					p = p->brother;
				}
				if (p->brother != NULL)//若不是排在兄弟的末尾
				{
					q->brother = p->brother;
					p->brother = q;
					q->parent = p->parent;
				}
				else//若排在兄弟的末尾
				{
					p->brother = q;
					q->parent = p->parent;
				}

			}
		}
	}
	return true;
}

template <class ElemType>
TreeNode<ElemType>* Genealogy<ElemType>::search(TreeNode<ElemType>* r, string n)
{
	TreeNode<ElemType>* q;
	if (r == NULL)return NULL;//没有家谱,头指针下为空
	if (n._Equal(r->data.name))return r;//比较姓名,看是否重名或是否存在
	if (r->brother)//家谱不为空,头指针下有这个人
	{
		q = search(r->brother, n);//在兄弟中找
		if (q)
			return q;//找到则返回指针q
	}
	if (r->child)
	{
		q = search(r->child, n);//在孩子中找
		if (q)
			return q;//找到则返回指针q
	}
	return NULL;//没有找到
}

template <class ElemType>
int Genealogy<ElemType>::generation(TreeNode<ElemType>* p)
{
	if (p == NULL)
		return 0;
	else
		return p->data.generation;
}

template <class ElemType>
bool Genealogy<ElemType>::Change(string n, Node newname)
{
	TreeNode<ElemType>* p, * q;
	p = search(root, n);//在族谱中查找要修改人的信息
	if (p == NULL) //判断是否有重名
	{
		settextcolor(RGB(254, 67, 101));//设置字体颜色
		settextstyle(200, 0, "楷体");//设置字体属性,宽度35,高度0(自适应),字体楷体
		outtextxy(300, 300, "查无此人!");
		cout << "此人不在家谱内" << endl;
		return false;//修改失败,返回false
	}
	q = search(root, newname.name);//在族谱中查询修改后的信息
	if (q != NULL && q != p)//判断是否存在,可与原名相同
	{
		settextcolor(RGB(254, 67, 101));//设置字体颜色
		settextstyle(200, 0, "楷体");//设置字体属性,宽度35,高度0(自适应),字体楷体
		outtextxy(300, 300, "此人已存在!");
		cout << "此人已在家谱内" << endl;
		return false;//修改失败,返回false
	}
	if (newname.birthyear > newname.deathyear)//若卒年小于生年,则不成立
	{
		settextcolor(RGB(254, 67, 101));//设置字体颜色
		settextstyle(200, 0, "楷体");//设置字体属性,宽度35,高度0(自适应),字体楷体
		outtextxy(300, 100, "修改失败!");
		settextstyle(100, 0, "楷体");//设置字体属性,宽度35,高度0(自适应),字体楷体
		outtextxy(300, 300, "卒年不能小于生年!!!");
		cout << "卒年小于生年" << endl;
		return false;
	}
	//由修改后的信息代替修改前的
	p->data.name = newname.name;
	p->data.birthyear = newname.birthyear;
	p->data.deathyear = newname.deathyear;
	//长幼有序问题
	if (p->parent == NULL)//若父节点为空,则为第一代族长,无需考虑长幼有序
	{
		return true;
	}
	if (p->parent->child == p)//若修改人原来为第一个孩子
	{
		TreeNode<ElemType>* t = p;
		while (t->brother != NULL && p->data.birthyear > t->brother->data.birthyear)//找的修改后的位置
		{
			t = t->brother;
		}
		p->parent->child = p->brother;
		if (t->brother != NULL)//若修改后到兄弟之间
		{
			p->brother = t->brother;
			t->brother = p;
		}
		else//若修改后为最小
		{
			t->brother = p;
			p->brother = NULL;
		}
	}
	else if (p->data.birthyear > p->parent->child->data.birthyear)//若原来不是第一个孩子,修改后也不是第一个孩子
	{
		TreeNode<ElemType>* t = p->parent->child, * k = p->parent->child;
		while (k->brother != p)//找到修改前的位置
		{
			k = k->brother;
		}
		if (p->brother != NULL)//若不是最后一个
			k->brother = p->brother;
		else//是最后一个
			k->brother = NULL;
		while (t->brother != NULL && p->data.birthyear > t->brother->data.birthyear)//找到修改后的位置
		{
			t = t->brother;
		}
		if (t->brother != NULL)//若不是最后一个
		{
			p->brother = t->brother;
			t->brother = p;
		}
		else//若是最后一个
		{
			t->brother = p;
			p->brother = NULL;
		}
	}
	else//修改前不是第一个,修改后是第一个
	{
		TreeNode<ElemType>* k = p->parent->child;
		while (k->brother != p)//找到修改前位置
		{
			k = k->brother;
		}
		if (p->brother != NULL)//若不是最后一个
			k->brother = p->brother;
		else//若是最后一个
			k->brother = NULL;
		p->brother = p->parent->child;
		p->parent->child = p;
	}
	cout << "修改成功!  " << p->data.name << " " << p->data.birthyear << " " << p->data.deathyear << " " << p->data.generation << " " << p->parent->data.name << endl;
	return true;
}

template <class ElemType>
bool Genealogy<ElemType>::Delete(string n)
{
	TreeNode<ElemType>* p;
	p = search(root, n);//在族谱中查询要删除的人
	if (p == NULL) //判断是否存在
	{
		settextcolor(RGB(254, 67, 101));//设置字体颜色
		settextstyle(200, 0, "楷体");//设置字体属性,宽度35,高度0(自适应),字体楷体
		outtextxy(300, 300, "查无此人!");
		cout << "此人不在家谱内" << endl;
		return false;//删除失败,返回false
	}
	if (p->parent == NULL)//若要删除人的父亲节点为空
	{
		delete p;
		p = NULL;
		return true;
	}
	TreeNode<ElemType>* q = p->parent;
	if (q->child == p)//若要删除人为第一个孩子
	{
		q->child = p->brother;
		delete p;
		p = NULL;
	}
	else//若不是第一个孩子
	{
		TreeNode<ElemType>* q1 = q->child;
		while (q1->brother != p)//找到删除节点前一个兄弟的节点
		{
			q1 = q1->brother;
		}
		q1->brother = p->brother;
		delete p;
		p = NULL;
	}
	cout << "删除成功!" << endl;
	return true;
}

template <class ElemType>
void Genealogy<ElemType>::Savefile(TreeNode<ElemType>* r, fstream& file)
{
	if (r != NULL)
	{
		//将处理过后的数据存入文件中
		file << '\n';
		file << r->data.name;
		file << " ";
		file << r->data.birthyear;
		file << " ";
		file << r->data.deathyear;
		if (r->parent != NULL)//判断父亲是否为空
		{
			file << " ";
			file << r->parent->data.name;
		}

		//通过递归遍历整个树
		if (r->child != NULL)
		{
			Savefile(r->child, file);
		}
		if (r->brother != NULL)
		{
			Savefile(r->brother, file);
		}
	}
}

template <class ElemType>
void Genealogy<ElemType>::searchgeneration(TreeNode<ElemType>* p, int g, int k)
{
	if (k==1)
	{
		y = 200;
		k++;
	}
	if (p != NULL)
	{
		if (p->data.generation == g)//若此人的代数与所查询相同
		{
			Coutname(p);
			cout << " ";
			if (p->parent == NULL)//若其父亲为空
				Showmessage(y, 45, p->data.name, p->data.birthyear, p->data.deathyear, " ");//调用Showmessage函数,输出成员的信息
			else //不为空
				Showmessage(y, 45, p->data.name, p->data.birthyear, p->data.deathyear, p->parent->data.name);//调用Showmessage函数,输出成员的信息
			y += 50;//辅助数据,设置数据表格的输出位置
		}

		//利用递归,遍历整个族谱
		if (p->child != NULL)
		{
			searchgeneration(p->child, g, k);
		}
		if (p->brother != NULL)
		{
			searchgeneration(p->brother, g, k);
		}
	}
}

template <class ElemType>
bool Genealogy<ElemType>::searchchildren(string n, int y)
{
	TreeNode<ElemType>* p;
	p = search(root, n);//在族谱中查询此人
	if (p == NULL) //判断是否有重名
	{
		settextcolor(RGB(254, 67, 101));//设置字体颜色
		settextstyle(200, 0, "楷体");//设置字体属性,宽度35,高度0(自适应),字体楷体
		outtextxy(300, 300, "查无此人!");
		cout << "此人不在家谱内" << endl;
		return false;//查询失败,返回false
	}
	if (p->child != NULL)
	{
		Coutname(p->child);
		cout << " ";
		Showmessage(y, 45, p->child->data.name, p->child->data.birthyear, p->child->data.deathyear, p->data.name);//调用Showmessage函数,输出成员的信息
		y += 50;//辅助数据,设置数据表格的输出位置
		p = p->child;

		while (p->brother != NULL)//依次输出兄弟
		{
			Coutname(p->brother);
			cout << " ";
			Showmessage(y, 45, p->brother->data.name, p->brother->data.birthyear, p->brother->data.deathyear, p->brother->parent->data.name);
			y += 50;
			p = p->brother;
		}
	}
	return true;
}

template <class ElemType>
bool Genealogy<ElemType>::searchparent(string n)
{
	TreeNode<ElemType>* p;
	p = search(root, n);
	if (p == NULL) //判断是否有重名
	{
		settextcolor(RGB(254, 67, 101));//设置字体颜色
		settextstyle(200, 0, "楷体");//设置字体属性,宽度35,高度0(自适应),字体楷体
		outtextxy(300, 300, "查无此人!");
		cout << "此人不在家谱内" << endl;
		return false;//查询失败
	}
	if (p->parent == NULL)//判断父亲是否为空
	{
		settextcolor(RGB(254, 67, 101));//设置字体颜色
		settextstyle(180, 0, "楷体");//设置字体属性,宽度35,高度0(自适应),字体楷体
		outtextxy(300, 300, "此人为第一代!");
		cout << "此人为第一代!" << endl;
		return false;//查询失败
	}
	Coutname(p->parent);
	Showmessage(400, p->parent->data.name, p->parent->data.birthyear, p->parent->data.deathyear, p->parent->parent->data.name);//调用Showmessage函数,输出成员的信息
	return true;
}

template <class ElemType>
void Genealogy<ElemType>::searchbrother(string n, int y)
{
	TreeNode<ElemType>* p;
	p = search(root, n);
	if (p == NULL) //判断是否有重名
	{
		settextcolor(RGB(254, 67, 101));//设置字体颜色
		settextstyle(200, 0, "楷体");//设置字体属性,宽度35,高度0(自适应),字体楷体
		outtextxy(300, 300, "查无此人!");
		cout << "此人不在家谱内" << endl;
		return;
	}
	if (p->parent == NULL)//判断父亲是否为空
	{
		settextcolor(RGB(254, 67, 101));//设置字体颜色
		settextstyle(170, 0, "楷体");//设置字体属性,宽度35,高度0(自适应),字体楷体
		outtextxy(280, 300, "此人为一代族长");
		return;
	}
	if (p->parent->child != p)//若不是第一个孩子
	{
		settextcolor(RGB(118, 77, 57));//设置字体颜色
		settextstyle(80, 0, "楷体");//设置字体属性,宽度35,高度0(自适应),字体楷体
		outtextxy(500, 10, "查询成功!");
		settextstyle(30, 0, "楷体");//设置字体属性,宽度35,高度0(自适应),字体楷体
		outtextxy(900, 30, "(若无数据输出,说明此人无兄弟)");
		Showtitle(100);//调用Showtitle函数,输出表头
		p = p->parent->child;
		Coutname(p);
		cout << " ";
		Showmessage(y, 45, p->data.name, p->data.birthyear, p->data.deathyear, p->parent->data.name);//调用Showmessage函数,输出成员的信息
		y += 50;//辅助数据,设置数据表格的输出位置
		while (p->brother != NULL)
		{
			if (p->brother->data.name == n)//若为所查之人,则跳过
			{
				p = p->brother;
				continue;
			}
			Coutname(p->brother);
			cout << " ";
			Showmessage(y, 45, p->brother->data.name, p->brother->data.birthyear, p->brother->data.deathyear, p->brother->parent->data.name);
			y += 50;
			p = p->brother;
		}
	}
	else//若为第一个孩子,输出他的全部兄弟
	{
		while (p->brother != NULL)
		{
			Coutname(p->brother);
			cout << " ";
			Showmessage(y, 45, p->brother->data.name, p->brother->data.birthyear, p->brother->data.deathyear, p->brother->parent->data.name);
			y += 50;
			p = p->brother;
		}
	}
}

template <class ElemType>
void Genealogy<ElemType>::Showmessage(int y, string n, int b, int d, string f)
{
	button b1, b2, b3, b4, b5;
	b1.build(300, y, 190, 90, RGB(107, 194, 53), n.data());
	b1.drawbutton();
	b2.build(500, y, 190, 90, RGB(107, 194, 53), to_string(b).data());
	b2.drawbutton();
	b3.build(700, y, 190, 90, RGB(107, 194, 53), to_string(d).data());
	b3.drawbutton();
	b4.build(900, y, 190, 90, RGB(107, 194, 53), to_string(generation(search(root, n))).data());
	b4.drawbutton();
	b5.build(1100, y, 190, 90, RGB(107, 194, 53), f.data());
	b5.drawbutton();
}

template <class ElemType>
void Genealogy<ElemType>::Showmessage(int y, int h, string n, int b, int d, string f)
{
	button b1, b2, b3, b4, b5;
	b1.build(300, y, 190, h, RGB(107, 194, 53), n.data());
	b1.drawbutton();
	b2.build(500, y, 190, h, RGB(107, 194, 53), to_string(b).data());
	b2.drawbutton();
	b3.build(700, y, 190, h, RGB(107, 194, 53), to_string(d).data());
	b3.drawbutton();
	b4.build(900, y, 190, h, RGB(107, 194, 53), to_string(generation(search(root, n))).data());
	b4.drawbutton();
	b5.build(1100, y, 190, h, RGB(107, 194, 53), f.data());
	b5.drawbutton();
}

template <class ElemType>
void Genealogy<ElemType>::Showtitle()
{
	button b0, b1, b2, b3, b4;
	b0.build(300, 300, 190, 90, RGB(6, 128, 67), "姓名");
	b0.drawbutton();
	b1.build(500, 300, 190, 90, RGB(6, 128, 67), "出生日期");
	b1.drawbutton();
	b2.build(700, 300, 190, 90, RGB(6, 128, 67), "死亡日期");
	b2.drawbutton();
	b3.build(900, 300, 190, 90, RGB(6, 128, 67), "第几代");
	b3.drawbutton();
	b4.build(1100, 300, 190, 90, RGB(6, 128, 67), "父亲");
	b4.drawbutton();
}
template <class ElemType>
void Genealogy<ElemType>::Showtitle(int y)
{
	button b0, b1, b2, b3, b4;
	b0.build(300, y, 190, 90, RGB(6, 128, 67), "姓名");
	b0.drawbutton();
	b1.build(500, y, 190, 90, RGB(6, 128, 67), "出生日期");
	b1.drawbutton();
	b2.build(700, y, 190, 90, RGB(6, 128, 67), "死亡日期");
	b2.drawbutton();
	b3.build(900, y, 190, 90, RGB(6, 128, 67), "第几代");
	b3.drawbutton();
	b4.build(1100, y, 190, 90, RGB(6, 128, 67), "父亲");
	b4.drawbutton();
}

template <class ElemType>
void Genealogy<ElemType>::Coutallmessage(TreeNode<ElemType>* r, int k) {

	/*if (r != NULL)   //字符界面输出族谱
	{
		for (int j = i - 1; j > 0; j--)
		{
			cout << "        ";
		}
		cout << "|->";
		Coutname(r);
		cout << endl;

		if (r->child != NULL)
		{
			i++;
			Coutallmessage(r->child);
			i--;
		}
		if (r->brother != NULL)
		{
			Coutallmessage(r->brother);
		}
	}*/
	if (k == 1)//每次展示族谱前,刷新k值
	{
		y = 20;
		k++;//修改k值,防止在一次运行中重复刷新
	}
	if (r != NULL)
	{
		x = 400;
		for (int j = i - 1; j > 0; j--)
		{
			x += 150;//设置输出数据的x轴
		}
		Showname(r, x, y);//调用Showname函数输出数据,x,y设置位置
		y += 30;//每输出一个数据y坐标下移

		if (r->child != NULL)
		{
			i++;//若为孩子x坐标右移
			y -= 30;//y轴无需下移,则回退
			Coutallmessage(r->child, k);//用递归函数,遍历整个族谱
			y += 15;//若一脉输出结束,则隔开一段距离,以示区分
			i--;//一脉结束x轴回退
		}
		if (r->brother != NULL)
		{
			Coutallmessage(r->brother, k);//用递归函数,遍历整个族谱
		}
	}
	else
	{
		settextcolor(RGB(130,57,53));//设置字体颜色
		settextstyle(200, 0, "楷体");//设置字体属性,高度200,宽度0(自适应),字体楷体
		outtextxy(300, 300, "族谱为空!");//在easyX界面输出文字,设置左上角坐标、文字内容
	}
}

button.h

easyX界面上按钮的输出

//button.h
#pragma once
#include<graphics.h>
#include<string>
#include<conio.h>
class button    //按键
{
public:
	int x;
	int y;//(x,y)按键左上角的位置
	int width;//按键宽度
	int height;//按键高度
	COLORREF color;//按键的颜色,颜色全部都是大写的英文单词
	char* str;//按键上的字
	void build(int x_, int y_, int width_, int height_, COLORREF color_, const char* str_) //对按键进行初始化,分别初始化其位置,宽,高,颜色,文字
	{
		x = x_;
		y = y_;
		width = width_;
		height = height_;
		color = color_;
		str = new char[strlen(str_) + 1];//字符指针需要预先分配内存
		strcpy(str, str_);//复制字符串
	}
	void drawbutton()//画出按键
	{
		setfillcolor(color);//设置填充的颜色为按键的颜色
		settextstyle(20, 0, "楷体");//设置字体属性,宽度35,高度0(自适应),字体楷体
		setlinecolor(BLACK);//设置边框线条颜色
		settextcolor(BLACK);//设置字体颜色
		setbkmode(TRANSPARENT);//设置字体背景为透明treansparent
		fillrectangle(x, y, x + width, y + height);//填充出一个矩形,参数为该矩形的左上和右下的坐标,颜色为上面所设置的颜色默认为黑色
		RECT r = { x, y, x + width, y + height };//设置文字位置
		drawtext(str, &r, DT_CENTER | DT_VCENTER | DT_SINGLELINE);//输出设置好的字体文字str
	}
	//鼠标交互的一部分
	bool mouseInButton(MOUSEMSG m)//用于判断鼠标是否在按键的范围内
	{
		//m.x,m.y表示该鼠标的横纵坐标
		if (m.x >= x && m.x <= x + width && m.y >= y && m.y <= y + height)
		{
			color = RED;//如果在就将按键颜色改变
			return true;
		}
		else
		{
			color = RGB(251, 178, 23);//变回来
			return false;
		}
	}
	~button() {//析构函数
		delete[]str;
	}
};

主函数

完成各个类的合理连接及主界面的设计(关于png图片去除透明部分代码参考 https://blog.csdn.net/weixin_45779485/article/details/102757315)

#include<graphics.h>
#include<conio.h>
#include<iostream>
#include<fstream>
#include"button.h"
#include"Genealogy.h"
#include"Genealogy.cpp"
#include"TreeNode.h"
#include"Node.h"
using namespace std;
//使用easyX制作界面,需将 项目->属性->配置属性->高级->字符集 改为 使用多字节字符集
//使用strcpy,需将 项目->属性->C/C++ ->SDL属性 改为否

// 载入PNG图并去透明部分
void drawAlpha(IMAGE* picture, int  picture_x, int picture_y) //x为载入图片的X坐标,y为Y坐标
{

	// 变量初始化
	DWORD* dst = GetImageBuffer();    // GetImageBuffer()函数,用于获取绘图设备的显存指针,EASYX自带
	DWORD* draw = GetImageBuffer();
	DWORD* src = GetImageBuffer(picture); //获取picture的显存指针
	int picture_width = picture->getwidth(); //获取picture的宽度,EASYX自带
	int picture_height = picture->getheight(); //获取picture的高度,EASYX自带
	int graphWidth = getwidth();       //获取绘图区的宽度,EASYX自带
	int graphHeight = getheight();     //获取绘图区的高度,EASYX自带
	int dstX = 0;    //在显存里像素的角标

	// 实现透明贴图 公式: Cp=αp*FP+(1-αp)*BP , 贝叶斯定理来进行点颜色的概率计算
	for (int iy = 0; iy < picture_height; iy++)
	{
		for (int ix = 0; ix < picture_width; ix++)
		{
			int srcX = ix + iy * picture_width; //在显存里像素的角标
			int sa = ((src[srcX] & 0xff000000) >> 24); //0xAArrggbb;AA是透明度
			int sr = ((src[srcX] & 0xff0000) >> 16); //获取RGB里的R
			int sg = ((src[srcX] & 0xff00) >> 8);   //G
			int sb = src[srcX] & 0xff;              //B
			if (ix >= 0 && ix <= graphWidth && iy >= 0 && iy <= graphHeight && dstX <= graphWidth * graphHeight)
			{
				dstX = (ix + picture_x) + (iy + picture_y) * graphWidth; //在显存里像素的角标
				int dr = ((dst[dstX] & 0xff0000) >> 16);
				int dg = ((dst[dstX] & 0xff00) >> 8);
				int db = dst[dstX] & 0xff;
				draw[dstX] = ((sr * sa / 255 + dr * (255 - sa) / 255) << 16)  //公式: Cp=αp*FP+(1-αp)*BP  ; αp=sa/255 , FP=sr , BP=dr
					| ((sg * sa / 255 + dg * (255 - sa) / 255) << 8)         //αp=sa/255 , FP=sg , BP=dg
					| (sb * sa / 255 + db * (255 - sa) / 255);              //αp=sa/255 , FP=sb , BP=db
			}
		}
	}
}

int main()
{
	string name1,name2, fathername;
	int birthday, deathday;
	TreeNode<Node>* r=new TreeNode<Node>();
	Genealogy<Node> genealogy(r,0);
	fstream file1;
	file1.open("C:\\Users\\wang\\Desktop\\Genghis Khan.txt", ios::in);//打开文件Genghis Khan.txt//只读打开//根据文件在电脑中的位置调整
	if (file1.fail())
	{
		cout << "error!" << endl;
		exit(1);
	}
	genealogy.InitTree(file1);//根据文件信息,初始化族谱
	file1.close();
	//使用easyX制作界面
	initgraph(1500, 800, SHOWCONSOLE);//初始化一个1500*800大小的图形窗口
	IMAGE backgroung;//设置背景
	loadimage(&backgroung, "C:\\Users\\wang\\Desktop\\backgroung.jpg", 1500, 800, 1);//下载背景图片//根据图片在电脑中的位置调整
	putimage(0, 0, &backgroung);//显示背景图片
	button b1, b2, b3, b4, b5, b6, b7;//定义7个按钮,分别为 显示族谱、添加成员、修改成员、删除成员、查询、保存、退出
	b1.build(20, 50, 150, 50, RGB(251, 178, 23), "显示族谱");//创建一个按钮,设置按钮左上角坐标x、y,宽,高,颜色,按钮文字
	b1.drawbutton();//将按键画出
	b2.build(20, 150, 150, 50, RGB(251, 178, 23), "添加成员");
	b2.drawbutton();
	b3.build(20, 250, 150, 50, RGB(251, 178, 23), "修改成员");
	b3.drawbutton();
	b4.build(20, 350, 150, 50, RGB(251, 178, 23), "删除成员");
	b4.drawbutton();
	b5.build(20, 450, 150, 50, RGB(251, 178, 23), "查询");
	b5.drawbutton();
	b6.build(20, 550, 150, 50, RGB(251, 178, 23), "保存");
	b6.drawbutton();
	b7.build(20, 650, 150, 50, RGB(251, 178, 23), "退出");
	b7.drawbutton();
	while (1)
	{
		//更新按键与背景,对按键进行重新绘制
		BeginBatchDraw();//使界面显示更稳定
		putimage(0, 0, &backgroung);
		b1.drawbutton();
		b2.drawbutton();
		b3.drawbutton();
		b4.drawbutton();
		b5.drawbutton();
		b6.drawbutton();
		b7.drawbutton();
		MOUSEMSG m = GetMouseMsg();//定义一个鼠标信息变量并初始化为现在的鼠标信息
		if (b1.mouseInButton(m) && m.uMsg == WM_LBUTTONDOWN)//显示族谱
		{
			settextcolor(RGB(161,23,21));//设置字体颜色
			settextstyle(18, 0, "楷体");//设置字体属性,高度100,宽度0(自适应),字体楷体
			outtextxy(425, 1, "第一代");//在easyX界面输出文字,设置左上角坐标、输出文字内容
			outtextxy(575, 1, "第二代");//在easyX界面输出文字,设置左上角坐标、输出文字内容
			outtextxy(725, 1, "第三代");//在easyX界面输出文字,设置左上角坐标、输出文字内容
			outtextxy(875, 1, "第四代");//在easyX界面输出文字,设置左上角坐标、输出文字内容
			outtextxy(1025, 1, "第五代");//在easyX界面输出文字,设置左上角坐标、输出文字内容
			outtextxy(1175, 1, "第六代");//在easyX界面输出文字,设置左上角坐标、输出文字内容
			outtextxy(1325, 1, "第七代");//在easyX界面输出文字,设置左上角坐标、输出文字内容

			genealogy.Coutallmessage(genealogy.getroot(),1);//调用Coutallmessage函数显示族谱
			button b;//设置“返回”按钮,防止显示结果被直接刷新
			b.build(1400, 750, 80, 40, RGB(251, 178, 23), "返回");
			b.drawbutton();
			while (1)
			{
				//更新按键,对按键进行重新绘制
				BeginBatchDraw();//使界面显示更稳定
				b.drawbutton();
				MOUSEMSG m1 = GetMouseMsg();//定义一个鼠标信息变量并初始化为现在的鼠标信息
				if (b.mouseInButton(m1) && m1.uMsg == WM_LBUTTONDOWN)
				{
					break;//跳出此循环
				}
				FlushBatchDraw();
			}
		}
		else if (b2.mouseInButton(m) && m.uMsg == WM_LBUTTONDOWN)//添加成员
		{
			bool flag;//设置布尔值,接收Addperson传回的布尔类型,从而判断成员是否添加成功
			cout << "请输入 本人名字、出生日期、死亡日期、父亲名字 :";
			cin >> name1 >> birthday >> deathday >> fathername;//输入 本人名字、出生日期、死亡日期、父亲名字 的数据
			flag = genealogy.Addperson(name1, birthday, deathday, fathername);//调用Addperson函数,添加成员
			if (flag)//若返回值为true,则说明添加成功
			{
				//RECT r = { 500, 100, 1000 , 300 };
							//drawtext("添加成功!", &r, DT_CENTER | DT_VCENTER | DT_SINGLELINE);//输出设置好的字体文字str
				settextcolor(RGB(174, 221, 129));//设置字体颜色
				settextstyle(100, 0, "楷体");//设置字体属性,高度100,宽度0(自适应),字体楷体
				outtextxy(500, 100, "添加成功!");//在easyX界面输出文字,设置左上角坐标、输出文字内容
				genealogy.Showtitle();//调用Showtitle函数,输出表头 “本人名字、出生日期、死亡日期、第几代、父亲名字 ”
				genealogy.Showmessage(400, name1, birthday, deathday, fathername);//调用Showmessage函数,输出添加成员的信息
				cout << "添加成功!  " << name1 << " " << birthday << " " << deathday << " " << genealogy.generation(genealogy.search(genealogy.getroot(), name1)) << " " << fathername << endl;
			}
			button b;//设置“返回”按钮,防止显示结果被直接刷新
			b.build(1400, 750, 80, 40, RGB(251,178,23), "返回");
			b.drawbutton();
			while (1)
			{
				//更新按键,对按键进行重新绘制
				BeginBatchDraw();//使界面显示更稳定
				b.drawbutton();
				MOUSEMSG m1 = GetMouseMsg();//定义一个鼠标信息变量并初始化为现在的鼠标信息
				if (b.mouseInButton(m1) && m1.uMsg == WM_LBUTTONDOWN)
				{
					break;//跳出此循环
				}
				FlushBatchDraw();
			}
		}
		else if (b3.mouseInButton(m) && m.uMsg == WM_LBUTTONDOWN)//修改成员
		{
			bool flag;//设置布尔值,接收Change传回的布尔类型,从而判断成员是否修改成功
			cout << "请输入 要修改人姓名 :";
			cin >> name1;//输入修改人姓名
			TreeNode<Node>* p = genealogy.search(genealogy.getroot(), name1);//调用search函数判断修改人是否在族谱中
			if (p == NULL) //判断是否有重名,若p==NULL说明族谱中没有此人
			{
				settextcolor(RGB(254, 67, 101));//设置字体颜色
				settextstyle(200, 0, "楷体");//设置字体属性,高度200,宽度0(自适应),字体楷体
				outtextxy(300, 300, "查无此人!");//在easyX界面输出文字,设置左上角坐标、文字内容
				cout << "此人不在家谱内" << endl;
				button b;//设置“返回”按钮,防止显示结果被直接刷新
				b.build(1400, 750, 80, 40, RGB(251, 178, 23), "返回");
				b.drawbutton();
				while (1)
				{
					//更新按键,对按键进行重新绘制
					BeginBatchDraw();//使界面显示更稳定
					b.drawbutton();
					MOUSEMSG m1 = GetMouseMsg();//定义一个鼠标信息变量并初始化为现在的鼠标信息
					if (b.mouseInButton(m1) && m1.uMsg == WM_LBUTTONDOWN)
					{
						break;//跳出此循环
					}
					FlushBatchDraw();
				}
				continue;//跳过此if判断下的后续步骤,返回主循环继续执行
			}
			if (p->parent==NULL)
			{
				cout << "要修改人信息为:姓名:" << p->data.name << " 出生日期:" << p->data.birthyear << " 死亡日期:" << p->data.deathyear << " 第几代:" << p->data.generation << endl;
				genealogy.Showmessage(400, name1, p->data.birthyear, p->data.deathyear, " ");//调用Showmessage函数,输出要修改成员的信息
			}
			else
			{
				cout << "要修改人信息为:姓名:" << p->data.name << " 出生日期:" << p->data.birthyear << " 死亡日期:" << p->data.deathyear << " 第几代:" << p->data.generation << " 父亲:" << p->parent->data.name << endl;
				genealogy.Showmessage(400, name1, p->data.birthyear, p->data.deathyear, p->parent->data.name);//调用Showmessage函数,输出要修改成员的信息
			}
			cout << "请输入 修改后名字、出生日期、死亡日期 :";
			cin >> name2 >> birthday >> deathday;//输入修改后信息
			Node d(name2, birthday, deathday);
			flag = genealogy.Change(name1, d);//调用Change函数,修改成员信息
			if (flag)//若返回值为true,则说明修改成功
			{
				settextcolor(RGB(250, 227, 113));//设置字体颜色
				settextstyle(100, 0, "楷体");//设置字体属性,高度100,宽度0(自适应),字体楷体
				outtextxy(500, 100, "修改成功!");//在easyX界面输出文字,设置左上角坐标、文字内容
				genealogy.Showtitle();//调用Showtitle函数,输出表头 “本人名字、出生日期、死亡日期、第几代、父亲名字 ”
				settextcolor(RGB(230, 179, 61));//设置字体颜色
				settextstyle(60, 0, "楷体");//设置字体属性,高度60,宽度0(自适应),字体楷体
				outtextxy(500, 520, "修改为↓");//在easyX界面输出文字,设置左上角坐标、文字内容
				if (p->parent==NULL)
					genealogy.Showmessage(600, name2, birthday, deathday, " ");//调用Showmessage函数,输出修改后成员的信息
				else
					genealogy.Showmessage(600, name2, birthday, deathday, p->parent->data.name);//调用Showmessage函数,输出修改后成员的信息
			}
			button b;//设置“返回”按钮,防止显示结果被直接刷新
			b.build(1400, 750, 80, 40, RGB(251, 178, 23), "返回");
			b.drawbutton();
			while (1)
			{
				//更新按键,对按键进行重新绘制
				BeginBatchDraw();//使界面显示更稳定
				b.drawbutton();
				MOUSEMSG m1 = GetMouseMsg();//定义一个鼠标信息变量并初始化为现在的鼠标信息
				if (b.mouseInButton(m1) && m1.uMsg == WM_LBUTTONDOWN)
				{
					break;//跳出此循环
				}
				FlushBatchDraw();
			}
		}
		else if (b4.mouseInButton(m) && m.uMsg == WM_LBUTTONDOWN)//删除成员
		{
			bool flag;//设置布尔值,接收Delete传回的布尔类型,从而判断成员是否删除成功
			cout << "请输入要删除人的姓名:";
			cin >> name1;//输入 要删除人的姓名
			flag = genealogy.Delete(name1);//调用Delete函数删除name1的信息
			if (flag)//若返回值为true,则说明删除成功
			{
				settextcolor(RGB(254, 67, 101));//设置字体颜色
				settextstyle(200, 0, "楷体");//设置字体属性,高度200,宽度0(自适应),字体楷体
				outtextxy(300, 300, "删除成功!");   //在easyX界面输出文字,设置左上角坐标、文字内容
				settextstyle(50, 0, "楷体");//设置字体属性,高度50,宽度0(自适应),字体楷体
				outtextxy(300, 500, "已经将");       //在easyX界面输出文字,设置左上角坐标、文字内容
				outtextxy(500, 500, name1.data());   //在easyX界面输出文字,设置左上角坐标、文字内容
				outtextxy(800, 500, "一脉清出族谱"); //在easyX界面输出文字,设置左上角坐标、文字内容
			}
			button b;//设置“返回”按钮,防止显示结果被直接刷新
			b.build(1400, 750, 80, 40, RGB(251, 178, 23), "返回");
			b.drawbutton();
			while (1)
			{
				//更新按键,对按键进行重新绘制
				BeginBatchDraw();//使界面显示更稳定
				b.drawbutton();
				MOUSEMSG m1 = GetMouseMsg();//定义一个鼠标信息变量并初始化为现在的鼠标信息
				if (b.mouseInButton(m1) && m1.uMsg == WM_LBUTTONDOWN)
				{
					break;//跳出此循环
				}
				FlushBatchDraw();
			}
		}
		else if (b5.mouseInButton(m) && m.uMsg == WM_LBUTTONDOWN)//查询
		{
			IMAGE backgroung0;//设置背景
			loadimage(&backgroung0, "C:\\Users\\wang\\Desktop\\search.png", 1280, 780, 1);//下载背景图片//根据文件在电脑中的位置调整
			button b10, b11, b12, b13, b14, b15;//按姓名,按代,查孩子,查父亲,查兄弟, 返回
			b10.build(100, 100, 100, 50, RGB(251, 178, 23), "按姓名查");//创建一个按钮,设置按钮左上角坐标x、y,宽,高,颜色,按钮文字
			b10.drawbutton();//将按键画出
			b11.build(100, 200, 100, 50, RGB(251, 178, 23), "按代查");
			b11.drawbutton();
			b12.build(100, 300, 100, 50, RGB(251, 178, 23), "查孩子");
			b12.drawbutton();
			b13.build(100, 400, 100, 50, RGB(251, 178, 23), "查父亲");
			b13.drawbutton();
			b14.build(100, 500, 100, 50, RGB(251, 178, 23), "查兄弟");
			b14.drawbutton();
			b15.build(100, 600, 100, 50, RGB(251, 178, 23), "返回");
			b15.drawbutton();
			while (1)
			{
				//更新按键和背景,对按键进行重新绘制
				BeginBatchDraw();//使界面显示更稳定
				putimage(0, 0, &backgroung);
				drawAlpha(&backgroung0, 210, 10);
				//putimage(210, 10, &backgroung0);
				b10.drawbutton();
				b11.drawbutton();
				b12.drawbutton();
				b13.drawbutton();
				b14.drawbutton();
				b15.drawbutton();
				MOUSEMSG m = GetMouseMsg();//定义一个鼠标信息变量并初始化为现在的鼠标信息
				if (b10.mouseInButton(m) && m.uMsg == WM_LBUTTONDOWN)//按姓名查
				{
					TreeNode<Node>* p;
					cout << "输入要查询的姓名:";
					cin >> name1;//输入要查询的姓名
					p=genealogy.search(genealogy.getroot(), name1);//调用search函数,查询name1的信息
					if (p == NULL) //判断是否有重名
					{
						cout << "此人不在家谱内" << endl;
						settextcolor(RGB(118, 77, 57));//设置字体颜色
						settextstyle(200, 0, "楷体");//设置字体属性,高度200,宽度0(自适应),字体楷体
						outtextxy(300, 300, "查无此人!");//在easyX界面输出文字,设置左上角坐标、文字内容
					}
					else 
					{
						settextcolor(RGB(118,77, 57));//设置字体颜色
						settextstyle(100, 0, "楷体");//设置字体属性,高度100,宽度0(自适应),字体楷体
						outtextxy(500, 100, "查询成功!");//在easyX界面输出文字,设置左上角坐标、文字内容
						genealogy.Showtitle();//调用Showtitle函数,输出表头 “本人名字、出生日期、死亡日期、第几代、父亲名字 ”
						if (p->parent==NULL)
						{
							cout << "姓名:" << p->data.name << " 出生日期:" << p->data.birthyear << " 死亡日期:" << p->data.deathyear << " 第几代:" << p->data.generation << endl;
							genealogy.Showmessage(400, p->data.name, p->data.birthyear, p->data.deathyear, " ");//调用Showmessage函数,输出成员的信息
						}
						else
						{
						cout << "姓名:" << p->data.name << " 出生日期:" << p->data.birthyear << " 死亡日期:" << p->data.deathyear << " 第几代:" << p->data.generation << " 父亲:" << p->parent->data.name << endl;
						genealogy.Showmessage(400, p->data.name, p->data.birthyear, p->data.deathyear, p->parent->data.name);//调用Showmessage函数,输出成员的信息
						}
					}

					button b;//设置“返回”按钮,防止显示结果被直接刷新
					b.build(1400, 750, 80, 40, RGB(251, 178, 23), "返回");
					b.drawbutton();
					while (1)
					{
						//更新按键,对按键进行重新绘制
						BeginBatchDraw();//使界面显示更稳定
						b.drawbutton();
						MOUSEMSG m1 = GetMouseMsg();//定义一个鼠标信息变量并初始化为现在的鼠标信息
						if (b.mouseInButton(m1) && m1.uMsg == WM_LBUTTONDOWN)
						{
							break;//跳出此循环
						}
						FlushBatchDraw();
					}
				}
				else if (b11.mouseInButton(m) && m.uMsg == WM_LBUTTONDOWN)//按代查
				{
					cout << "输入要查哪一代:";
					int genera;
					cin >> genera;
					genealogy.searchgeneration(genealogy.getroot(),genera,1);//调用searchgeneration函数,查询此代有那些人,y为辅助数据用来确定easyX界面上输出的表格位置
					settextcolor(RGB(118, 77, 57));//设置字体颜色
					settextstyle(80, 0, "楷体");//设置字体属性,高度80,宽度0(自适应),字体楷体
					outtextxy(500, 10, "查询成功!");//在easyX界面输出文字,设置左上角坐标、文字内容
					settextstyle(30, 0, "楷体");//设置字体属性,高度30,宽度0(自适应),字体楷体
					outtextxy(900, 30, "(若无数据输出,说明此代无人)");//在easyX界面输出文字,设置左上角坐标、文字内容
					genealogy.Showtitle(100);//调用Showtitle函数显示表头,添加参数y调整表头位置
					button b;//设置“返回”按钮,防止显示结果被直接刷新
					b.build(1400, 750, 80, 40, RGB(251, 178, 23), "返回");
					b.drawbutton();
					while (1)
					{
						//更新按键,对按键进行重新绘制
						BeginBatchDraw();//使界面显示更稳定
						b.drawbutton();
						MOUSEMSG m1 = GetMouseMsg();//定义一个鼠标信息变量并初始化为现在的鼠标信息
						if (b.mouseInButton(m1) && m1.uMsg == WM_LBUTTONDOWN)
						{
							break;//跳出此循环
						}
						FlushBatchDraw();
					}
				}
				else if (b12.mouseInButton(m) && m.uMsg == WM_LBUTTONDOWN)//查孩子
				{
					bool flag;
					cout << "输入要查询谁的孩子:";
					cin >> name1;
					flag = genealogy.searchchildren(name1,200);//调用searchchildren函数,查name1的孩子
					if (flag)
					{
						settextcolor(RGB(118, 77, 57));//设置字体颜色
						settextstyle(80, 0, "楷体");//设置字体属性,高度80,宽度0(自适应),字体楷体
						outtextxy(500, 10, "查询成功!");//在easyX界面输出文字,设置左上角坐标、文字内容
						settextstyle(30, 0, "楷体");//设置字体属性,高度30,宽度0(自适应),字体楷体
						outtextxy(900, 30, "(若无数据输出,说明此人无子)");//在easyX界面输出文字,设置左上角坐标、文字内容
						genealogy.Showtitle(100);//调用Showtitle函数显示表头,添加参数y调整表头位置
					}
					button b;//设置“返回”按钮,防止显示结果被直接刷新
					b.build(1400, 750, 80, 40, RGB(251, 178, 23), "返回");
					b.drawbutton();
					while (1)
					{
						//更新按键,对按键进行重新绘制
						BeginBatchDraw();//使界面显示更稳定
						b.drawbutton();
						MOUSEMSG m1 = GetMouseMsg();//定义一个鼠标信息变量并初始化为现在的鼠标信息
						if (b.mouseInButton(m1) && m1.uMsg == WM_LBUTTONDOWN)
						{
							break;//跳出此循环
						}
						FlushBatchDraw();
					}
				}
				else if (b13.mouseInButton(m) && m.uMsg == WM_LBUTTONDOWN)//查父亲
				{
					bool flag;
					cout << "输入要查询谁的父亲:";
					cin >> name1;
					flag = genealogy.searchparent(name1);//调用searchparent函数,查name1的父亲
					if (flag)
					{
						genealogy.Showtitle();//调用Showtitle函数显示表头
						settextcolor(RGB(118, 77, 57));//设置字体颜色
						settextstyle(90, 0, "楷体");//设置字体属性,高度90,宽度0(自适应),字体楷体
						outtextxy(500, 50, "查询成功!");//在easyX界面输出文字,设置左上角坐标、文字内容
						settextstyle(40, 0, "楷体");//设置字体属性,高度40,宽度0(自适应),字体楷体
						outtextxy(300, 150, "已查出");          //在easyX界面输出文字,设置左上角坐标、文字内容
						outtextxy(450, 150, name1.data());      //在easyX界面输出文字,设置左上角坐标、文字内容
						outtextxy(700, 150, "的父亲");          //在easyX界面输出文字,设置左上角坐标、文字内容
					}
					button b;//设置“返回”按钮,防止显示结果被直接刷新
					b.build(1400, 750, 80, 40, RGB(251, 178, 23), "返回");
					b.drawbutton();
					while (1)
					{
						//更新按键,对按键进行重新绘制
						BeginBatchDraw();//使界面显示更稳定
						b.drawbutton();
						MOUSEMSG m1 = GetMouseMsg();//定义一个鼠标信息变量并初始化为现在的鼠标信息
						if (b.mouseInButton(m1) && m1.uMsg == WM_LBUTTONDOWN)
						{
							break;//跳出此循环
						}
						FlushBatchDraw();
					}
				}
				else if (b14.mouseInButton(m) && m.uMsg == WM_LBUTTONDOWN)//查兄弟
				{
					cout << "输入要查询谁的兄弟:";
					cin >> name1;
					genealogy.searchbrother(name1,200);//调用searchbrother函数,查name1的兄弟
					button b;//设置“返回”按钮,防止显示结果被直接刷新
					b.build(1400, 750, 80, 40, RGB(251, 178, 23), "返回");
					b.drawbutton();
					while (1)
					{
						//更新按键,对按键进行重新绘制
						BeginBatchDraw();//使界面显示更稳定
						b.drawbutton();
						MOUSEMSG m1 = GetMouseMsg();//定义一个鼠标信息变量并初始化为现在的鼠标信息
						if (b.mouseInButton(m1) && m1.uMsg == WM_LBUTTONDOWN)
						{
							break;//跳出此循环
						}
						FlushBatchDraw();
					}
				}
				else if (b15.mouseInButton(m) && m.uMsg == WM_LBUTTONDOWN)//返回
				{
					break;//退出查询界面
				}
				FlushBatchDraw();
			}
		}
		else if (b6.mouseInButton(m) && m.uMsg == WM_LBUTTONDOWN)//保存
		{
			fstream file2;
			file2.open("C:\\Users\\wang\\Desktop\\Genghis Khan.txt", ios::out);//打开文件Genghis Khan.txt//写打开
			if (file2.fail())
			{
				cout << "error!" << endl;
				exit(1);
			}
			genealogy.Savefile(genealogy.getroot(), file2);//调用Savefile函数保存文件
			settextcolor(RGB(254, 67, 101));//设置字体颜色
			settextstyle(200, 0, "楷体");//设置字体属性,高度200,宽度0(自适应),字体楷体
			outtextxy(300, 300, "保存成功!"); //在easyX界面输出文字,设置左上角坐标、文字内容
			button b;//设置“返回”按钮,防止显示结果被直接刷新
			b.build(1400, 750, 80, 40, RGB(251, 178, 23), "返回");
			b.drawbutton();
			while (1)
			{
				//更新按键,对按键进行重新绘制
				BeginBatchDraw();//使界面显示更稳定
				b.drawbutton();
				MOUSEMSG m1 = GetMouseMsg();//定义一个鼠标信息变量并初始化为现在的鼠标信息
				if (b.mouseInButton(m1) && m1.uMsg == WM_LBUTTONDOWN)
				{
					break;//跳出此循环
				}
				FlushBatchDraw();
			}
		}
		else if (b7.mouseInButton(m) && m.uMsg == WM_LBUTTONDOWN)//退出
		{
			settextcolor(RGB(254, 67, 101));//设置字体颜色
			settextstyle(200, 0, "楷体");//设置字体属性,宽度35,高度0(自适应),字体楷体
			outtextxy(300, 300, "是否退出?");//在easyX界面输出文字,设置左上角坐标、文字内容
			button b, bb;//设置确认按钮,yes或no
			b.build(400, 550, 100, 50, RGB(251, 178, 23), "YES");
			bb.build(800, 550, 100, 50, RGB(251, 178, 23), "NO");
			b.drawbutton();//画出按钮
			bb.drawbutton();
			while (1)
			{
				//更新按键,对按键进行重新绘制
				BeginBatchDraw();//使界面显示更稳定
				b.drawbutton();
				bb.drawbutton();
				MOUSEMSG m1 = GetMouseMsg();//定义一个鼠标信息变量并初始化为现在的鼠标信息
				if (b.mouseInButton(m1) && m1.uMsg == WM_LBUTTONDOWN)//yes
				{
					break;//若同意则跳出此循环,关闭绘图窗口,结束任务进程
				}
				else if (bb.mouseInButton(m1) && m1.uMsg == WM_LBUTTONDOWN)//no
				{
					goto FLAG;//若不同意,则跳过退出程序,跳到FLAG处继续执行程序
				}
				FlushBatchDraw();
			}
			closegraph();			// 关闭绘图窗口
			return 0;
		FLAG:
			continue;//继续执行循环
		}
		FlushBatchDraw();
	}
}

Genghis Khan.txt

姓名 生年 卒年 父亲姓名(注意:铁木真为第一代,无父亲姓名)

铁木真 1162 1227
术赤 1178 1225 铁木真
拔都 1205 1255 术赤
察合台 1183 1241 铁木真
窝阔台 1186 1241 铁木真
贵由 1206 1248 窝阔台
忽察 1224 1274 贵由
脑忽 1226 1286 贵由
禾忽 1230 1260 贵由
阔端 1206 1251 窝阔台
阔出 1208 1236 窝阔台
拖雷 1193 1232 铁木真
蒙哥 1209 1259 拖雷
忽必烈 1215 1294 拖雷
朵儿只 1233 1240 忽必烈
真金 1243 1285 忽必烈
甘麻剌 1263 1302 真金
松山 1281 1328 甘麻剌
也孙铁木儿 1293 1328 甘麻剌
阿速吉八 1320 1328 也孙铁木儿
铁穆耳 1265 1307 真金
忙哥剌 1245 1280 忽必烈
那木罕 1250 1292 忽必烈
旭烈兀 1217 1265 拖雷
阿八哈 1234 1282 旭烈兀
贴古迭儿 1236 1284 旭烈兀
阿里不哥 1219 1266 拖雷
明理帖木儿 1238 1278 阿里不哥
药木忽儿 1245 1308 阿里不哥
阔列坚 1208 1238 铁木真

图片文件

backgroung.jpg(可以自己到网上找自己喜欢的背景图片)

族谱管理系统,课程设计,c++,数据结构

 search.png

族谱管理系统,课程设计,c++,数据结构

测试案例

程序运行后,会自动将GenghisKhan.txt中的内容读入到树中,然后进入主菜单界面。系统初始化测试用例如表1

表格 1系统初始化功能测试用例

字段名称

描述

测试项

系统初始化功能测试

输入标准

运行程序

输出标准

系统将GenghisKhan.txt中的内容读入到树中,结束后进入主菜单界面

程序主菜单界面功能测试用例如表2

表格 2程序主菜单界面功能测试用例

字段名称

描述

测试项

程序主菜单界面功能测试

输入标准

1.点击“显示族谱”按钮
2.点击“添加成员”按钮
3.点击“修改成员”按钮
4.点击“删除成员”按钮
5.点击“查询”按钮
6.点击“保存”按钮
7.点击“退出”按钮

输出标准

1.在easyX界面显示族谱信息
2.进行添加成员操作
3.进行修改成员操作
4.进行删除成员操作
5.进入查询子菜单界面
6.将树中信息保存到文本文件中,并在完成后在easyX界面显示“保存成功”。
7.进入退出系统界面

添加成员功能测试用例如表3

表格 3添加成员功能测试用例

字段名称

描述

测试项

添加成员功能测试

输入标准

点击“添加成员”按钮后,在控制台输入相关信息,点击回车

输出标准

若添加成功,则在easyX界面显示添加成功并显示添加人的信息
若添加失败,在easyX界面显示添加失败,并显示失败原因

修改成员功能测试用例如表4

表格 4修改成员功能测试用例

字段名称

描述

测试项

修改成员功能测试

输入标准

1.点击“修改成员”按钮后,在控制台输入要修改人姓名,点击回车
2.在控制台输入修改后的成员信息,点击回车

输出标准

1.若输入的修改人姓名不在族谱中,在easyX界面显示“查无此人”,结束修改进程若输入的修改人姓名在族谱中,则执行第二步
2.若输入的修改信息中卒年小于生年,则在easyX界面显示“修改失败”,并显示原因和修改前信息,若修改信息无误,则显示“修改成功”,并显示修改前后的信息对比

删除成员功能测试用例如表5

表格 5删除成员功能测试用例

字段名称

描述

测试项

删除成员功能测试

输入标准

点击“删除成员”按钮后,在控制台输入要删除人姓名,点击回车

输出标准

若输入的要删除人姓名不在族谱中,在easyX界面显示“查无此人”,结束修改进程,若输入的要删除人姓名在族谱中,则删除其及其子孙,并在easyX界面显示删除成功及删除人的名字

查询功能子菜单测试用例如表6

表格 6查询功能子菜单测试用例

字段名称

描述

测试项

查询功能子菜单测试

输入标准

1.点击“按姓名查”按钮
2.点击“按代查”按钮
3.点击“查孩子”按钮
4.点击“查父亲”按钮
5.点击“查兄弟”按钮
6.点击“返回”按钮

输出标准

1.进行按姓名查操作
2.进行按代查操作
3.进行查孩子操作
4.进行查父亲操作
5.进行查兄弟操作
6.返回主界面

按姓名查功能测试用例如表7

表格 7按姓名查功能测试用例

字段名称

描述

测试项

按姓名查功能测试

输入标准

点击“按姓名查”按钮后,在控制台输入要查询的姓名,点击回车

输出标准

若族谱中没有所查之人,在easyX界面输出“查无此人”,若查到所查之人,则显示查询成功及查询人信息。

按代查功能测试用例如表8

表格 8按代查功能测试用例

字段名称

描述

测试项

按代查功能测试

输入标准

点击“按代查”按钮后,在控制台输入要查询的代,点击回车

输出标准

在easyX界面显示所查询的代的成员

查孩子功能测试用例如表9

表格 9查孩子功能测试用例

字段名称

描述

测试项

查孩子功能测试

输入标准

点击“查孩子”按钮后,在控制台输入要查询人的名字,点击回车

输出标准

若查询人不在族谱中,则在easyX界面显示“查无此人”,若查到所查之人,这在easyX界面显示查询成功并显示其孩子的具体信息

查父亲功能测试用例如表10

表格 10查父亲功能测试用例

字段名称

描述

测试项

查父亲功能测试

输入标准

点击“查父亲”按钮后,在控制台输入要查询人的名字,点击回车

输出标准

若查询人不在族谱中,则在easyX界面显示“查无此人”,若查到所查之人,这在easyX界面显示查询成功并显示其父亲的具体信息,若所查之人为第一代,则显示“此人为第一代族长”

查兄弟功能测试用例如表11

表格 11查兄弟功能测试用例

字段名称

描述

测试项

查兄弟功能测试

输入标准

点击“查兄弟”按钮后,在控制台输入要查询人的名字,点击回车

输出标准

若查询人不在族谱中,则在easyX界面显示“查无此人”,若查到所查之人,这在easyX界面显示查询成功并显示其兄弟的具体信息,若所查之人为第一代,则显示“此人为第一代族长”

退出功能测试用例如表12

表格 12退出功能测试用例

字段名称

描述

测试项

退出功能测试

输入标准

1.点击“yes”按钮
2.点击“no”按钮

输出标准

1.退出成功,程序运行结束,退出进程
2.退出失败,程序继续运行,返回主菜单界面

结语

以上便是族谱管理系统的全部内容,希望可以对你产生帮助。文章来源地址https://www.toymoban.com/news/detail-771666.html

到了这里,关于课程设计---族谱管理系统(c++)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 超市管理系统 C++(课程设计)

    古之立大事者,不惟有超世之才,亦必有坚忍不拔之志。——苏轼 ---------------🍎------------🍉-------------- 🐼学编程的bird的博客,邀您一起学习🦌 ----------------🥕------------🥭------------- 😊很高兴你打开了这篇博客。 ★如有疑问不解或者说有想问的地方,都可以在下方评论留

    2024年01月16日
    浏览(31)
  • C++课程设计——学生成绩管理系统

    今天清理电脑偶尔发现一个我刚学编程时用c++写的一份课程设计,使用到简单的链表,结构体,c++类与对象的知识——学生成绩管理系统。 ~~ 系统结构: 管理员模式 教师模式 学生模式 实现了对学生成绩及信息的增删改查以及排序。 效果图 主菜单 管理员模式菜单 源代码

    2024年02月16日
    浏览(30)
  • C++课程设计:图书管理系统【附源码】

    课程设计目的   作为软件工程和计算机科学与技术专业的基本课程,课程设计不仅涵盖了C++语言的知识体系,又与工程的实际需要切实相关。通过课程设计的综合性训练,对开发者解决实际问题能力,编程能力,动手能力有很大的提升,更有助于样成良好的编程习惯。 图

    2024年02月07日
    浏览(28)
  • C++课程设计,题目:通讯录管理系统

              1、题目。            2、设计分析。            3、分模块分析。            4、代码实现。 一、题目。 通讯录管理系统 手机通讯录中的联系人的信息既可以存储在手机中,也可以存储在手机卡中,也可以同时存储在两个位置上(每个位置上的存储容量为10

    2024年02月11日
    浏览(26)
  • C语言版数据结构-课程设计-航空客运订票系统 V2.0 附源码(增加管理员功能)

    相信很多粉丝看过看过我的主页,有一个航空订票系统: 数据结构航空订票系统(附源码) 但是最近后台收到很多粉丝的要求,在上一个航空订票系统中要加上管理员的功能块,于是对上面那个课设进行了改进,新的功能流程如下: (航班信息由管理员添加和删除、顾客可

    2024年02月03日
    浏览(37)
  • (c++课程设计)简单车辆管理系统(有五种类型的车辆)代码+报告

    关于这个课程设计 ,差点没把我头发愁没。 好了其实本质还是东拼西凑,编程能力没怎么长进,花里胡哨的东西却学了不少 (不是) 万恶的学院,虽然要求三人一组,但是却分一二三类,三个人代码还不能互相抄袭。 最后每个人都要提交代码,完成报告,答辩。 我严重怀

    2024年02月11日
    浏览(20)
  • 系统分析与设计课程报告-----------------社团管理系统

    青年志愿者协会在学院党委的领导及团委的直接指导下,由学生自发组织,全校师生自愿参加的,志愿服务于广大师生,奉献爱心于社会的,倡导积极主流文化的群众性服务性团体。 (一)主席团 作为青年志愿者协会的领导核心,全面主持校青志的各项工作;负责校青志总

    2024年02月11日
    浏览(35)
  • 程序设计课程设计——学生学籍管理系统

    通过设计一个小型的应用系统,使学生进一步掌握面向对象的程序设计方法,运用C++中的类与对象的概念结合面向对象程序设计的思想,独立完成应用系统的设计,并养成良好的编程习惯。通过这个实践教学平台,培养学生对计算机应用系统的综合设计能力,培养学生正确分

    2024年02月09日
    浏览(38)
  • 【期末课程设计】学生成绩管理系统

    因其独特,因其始终如一 文章目录 一、学生成绩管理系统介绍 二、学生成绩管理系统设计思路 三、源代码 1. test.c  2. Student Management System.c 3.Stu_System.c 4.Teacher.c 5.Student Management System.h   前言: 学生成绩管理系统含教师登录入口和学生登录入口,可实现学生信息的添加,删

    2024年02月16日
    浏览(31)
  • 学生考勤管理系统设计_c++课程设计

    以下内容可且仅可供参考,如有错误欢迎指正。 部分内容借鉴自百度 侵删致歉 目录 前言 一、需求分析 二、详细设计 三、用户使用说明 四、总结与体会 五、参考文献 六、附录(源代码) 定义类 函数   1、问题描述 学生信息包括:学号、姓名、性别、年龄、班级等信息。

    2024年02月11日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包