家谱管理系统-二叉树孩子节点法-easyx图形化界面

 前段时间写了一个不完全的项目,虽然没有写完,但是还是很折磨人的

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<graphics.h>

//家族成员信息
typedef struct {
	int number;			//编号计数  这个编号肯定不为0,从自然数开始
	char name[20];		//名字
	int age;			//年龄
	char sex[10];		//男or女
}familyInformation;

//枚举变量
enum UI {			//mainUI不赋值默认从0开始
	MainUI,			// 主菜单
	CreatefamilyUI,	// 创建家谱界面
	FindNodeUI,		// 查找成员界面
	AddNodeUI,		// 添加成员界面
	ModifyUI,		// 修改成员界面
	PrintUI,		// 显示家谱界面
	DeleteUI,		// 删除成员界面
	SaveUI,			// 保存文件界面
	Exit			// 退出界面
}CurrentUI;

//孩子兄弟节点法(还有父节点)
typedef struct CSnode {
	familyInformation pos;		//这是引用了上面的匿名结构体
	int fatherId;				// 父节点编号
	struct CSnode* father;
	struct CSnode* firstchild, * nextchild;
}CSnode, * CSTree;//CSNode  强调节点   CSTree强调指针


//add用来输入家族成员的信息的
void add(familyInformation* emp) {

	char input[100] = { 0 };
	// 1. 输入编号
	if (InputBox(input, 200, "输入编号", "请输入家族成员编号:")) {
		sscanf(input, "%d", &emp->number);
	}
	sprintf(input, "编号: %d", emp->number);
	outtextxy(400, 200, input);

	// 2. 输入名字
	if (InputBox(input, 200, "输入姓名", "请输入家族成员姓名:")) {
		strncpy(emp->name, input, 20);
		emp->name[19] = '\0';
	}
	sprintf(input, "姓名: %s", emp->name);
	outtextxy(400, 250, input);

	// 3. 输入年龄
	if (InputBox(input, 200, "输入年龄", "请输入家族成员年龄:")) {
		sscanf(input, "%d", &emp->age);
	}
	sprintf(input, "年龄: %d", emp->age);
	outtextxy(400, 300, input);

	// 4. 输入性别
	if (InputBox(input, 200, "输入性别", "请输入家族成员性别:")) {
		sscanf(input, "%s", emp->sex);
	}
	sprintf(input, "性别: %s", emp->sex);
	outtextxy(400, 350, input);
}

// 全局根节点(家谱祖先)
CSTree root = NULL;

// 创建家谱
void createfamily() {
	if (root != NULL) {
		int result = MessageBox(NULL, "家谱已存在,无需重复创建!", "确认", MB_YESNO);
		return;
	}
	root = (CSnode*)malloc(sizeof(CSnode));
	if (root == NULL) {
		int result = MessageBox(NULL, "内存分配失败!", "确认", MB_YESNO);
		return;
	}
	root->father = NULL;
	root->firstchild = root->nextchild = NULL;
	add(&root->pos);// 添加家族成员信息
	// 简单返回提示
	settextcolor(YELLOW);
	outtextxy(350, 400, "点击任意位置返回主菜单");

	// 等待点击
	ExMessage msg;
	while (1) {
		if (peekmessage(&msg, EM_MOUSE) && msg.message == WM_LBUTTONDOWN) {
			CurrentUI = MainUI;
			break;
		}
		Sleep(10);
	}
	return;
}

// 查找家族成员(根据  目标编号==当前编号)
CSTree findNode(CSTree node, int number) {
	if (node == NULL) {
		int result = MessageBox(NULL, "家谱未创建!", "确认", MB_YESNO);
		return;
	}
	if (node->pos.number == number) {
		return node;
	}
	CSTree P = findNode(node->firstchild, number);
	if (P != NULL)return P;
	return findNode(node->nextchild, number);
}

// 添加家庭成员
void addNode() {
	if (root == NULL) {
		int result = MessageBox(NULL, "家谱未创建,请先创建家谱!", "确认", MB_YESNO);
		return;
	}

	int fatherNum;
	char input[100] = { 0 };
	// 1. 输入编号
	if (InputBox(input, 200, "输入编号", "请输入其父亲节点编号:")) {
		sscanf(input, "%d", &fatherNum);
	}

	//查找父节点
	CSTree father = findNode(root, fatherNum);
	if (father == NULL) {
		int result = MessageBox(NULL, "未找到指定父亲编号的成员!", "确认", MB_YESNO);
		return;
	}

	//创建新节点
	CSnode* newMember = (CSnode*)malloc(sizeof(CSnode));
	if (newMember == NULL) {
		int result = MessageBox(NULL, "内存分配失败!", "确认", MB_YESNO);
		return;
	}

	add(&newMember->pos);// 初始化新成员数据也就是下一个节点的信息
	newMember->father = father;
	newMember->firstchild = newMember->nextchild = NULL;

	if (father->firstchild == NULL) {
		father->firstchild = newMember;
	}
	else {//sibling的意思就是兄弟
		CSnode* sibling = father->firstchild;
		while (sibling->nextchild != NULL) {
			sibling = sibling->nextchild;
		}
		sibling->nextchild = newMember;
	}
}

// 修改成员信息
void modifyNode() {
	if (root == NULL) {
		int result = MessageBox(NULL, "家谱未创建,请先创建家谱!", "确认", MB_YESNO);
		return;
	}

	int number;
	char input[100] = { 0 };
	// 1. 输入编号
	if (InputBox(input, 200, "输入编号", "请输入家族成员编号:")) {
		sscanf(input, "%d", &number);
	}

	CSTree emp = findNode(root, number);
	if (emp == NULL) {
		int result = MessageBox(NULL, "未找到指定编号的成员信息!", "确认", MB_YESNO);
		return;
	}

	//printf("请输入新的成员信息\n");
	add(&emp->pos);
}


void drawFamilyTree(CSTree node, int x, int y, int level, int siblingOffset) {
	if (!node)return;

	char input[100] = { 0 };
	sprintf(input, "编号%d姓名%s %s %d岁", node->pos.number,node->pos.name,node->pos.sex,node->pos.age);
	setfillcolor(WHITE);

	settextstyle(20, 0, "宋体");

	int tx = x + (x - textwidth(input) / 2) / 2;
	int ty = y + (y - textheight(input) / 2) / 2;

	outtextxy(tx, ty+80, input);

	// 绘制子节点
	CSTree child = node->firstchild;
	int cx = x - 100 + siblingOffset * 500;
	int cy = y + 40;


	while (child) {
		// 递归绘制子树
		drawFamilyTree(child, cx, cy, level + 1, siblingOffset);

		child = child->nextchild;
		cx += 150; // 兄弟节点横向间距
		siblingOffset++;
	}
}

void printFamilyTree(CSTree node) {
	if (node == NULL) {
		int result = MessageBox(NULL, "家谱未创建,请先创建家谱!!", "确认", MB_YESNO);
		return;
	}
	cleardevice();//清空屏幕
	drawFamilyTree(node, 300, 50, 0, 0);

	//刷新显示
	FlushBatchDraw();
}

//你要删除的节点就是输入的节点
void deleteNode(CSTree node) {
	if (node == NULL) return;

	// 递归删除所有子树
	CSTree k = node->firstchild;
	while (k) {//k!=NULL;
		CSTree next = k->nextchild;
		deleteNode(k);
		k = next;
	}
	if (node->father) {
		CSTree p = node->father->firstchild;
		if (p == node) {
			node->father->firstchild = node->nextchild;
		}
		else {
			while (p->nextchild != node)p = p->nextchild;
			p->nextchild = node->nextchild;
		}
	}
	deleteNode(node->firstchild);
	free(node);
}

//删除节点还有其后代
void deleteFamily() {
	if (root == NULL) {
		int result = MessageBox(NULL, "家谱未创建,请先创建家谱!", "确认", MB_YESNO);
		return;
	}

	int number;
	char input2[100] = { 0 };
	// 1. 输入编号
	if (InputBox(input2, 200, "输入编号", "请输入家族成员编号:")) {
		sscanf(input2, "%d", &number);
	}

	CSTree emp = findNode(root, number);
	if (emp == NULL) {
		int result = MessageBox(NULL, "未找到该成员!", "确认", MB_YESNO);
		printf("未找到编号为%d的家族成员信息\n", number);
		return;
	}

	char input[100] = { 0 };
	// 1. 输入编号
	sscanf(input, "%d", &emp->pos.number);
	sprintf(input, "编号: %d", emp->pos.number);
	outtextxy(400, 200, input);

	// 2. 输入名字
	sprintf(input, "姓名: %s", emp->pos.name);
	outtextxy(400, 250, input);

	// 3. 输入年龄
	sscanf(input, "%d", &emp->pos.age);
	sprintf(input, "年龄: %d", emp->pos.age);
	outtextxy(400, 300, input);

	// 4. 输入性别
	sprintf(input, "性别: %s", emp->pos.sex);
	outtextxy(400, 350, input);
	//确认删除
	if (root == emp) {
		int number;
		char input[100] = { 0 };
		// 1. 输入编号
		if (InputBox(input, 200, "如果你确定要删除你整个的家谱,确定请输入1,否则为0", "请输入家族成员编号:")) {
			sscanf(input, "%d", &number);
		}
		if (number) {
			deleteNode(root);
			root = NULL;
		}
		return;
	}
	int result = MessageBox(NULL, "家族成员及其后代已经删除成功", "确认", MB_YESNO);
	deleteNode(emp);
}

// 保存当前节点核心数据
void saveFamily(CSTree node, FILE* fp) {
	if (!node || !fp) return;


	fwrite(&node->pos, sizeof(familyInformation), 1, fp);
	fwrite(&node->fatherId, sizeof(int), 1, fp);

	saveFamily(node->firstchild, fp);
	saveFamily(node->nextchild, fp);
}

void savefamilyToFile(CSTree  root) {
	FILE* fp = fopen("efe.dat", "ab");
	if (!fp)return;

	saveFamily(root, fp);
	fclose(fp);
}

// 从文件加载家谱(递归)
CSTree loadfamilyfromfile(CSTree parent,FILE* fp) {
	if (!fp || !parent)return NULL;
	
	// 读取节点数据
	CSnode* node = (CSnode*)malloc(sizeof(CSnode));
	fread(&node->pos, sizeof(familyInformation), 1, fp);
	fread(&node->fatherId, sizeof(int), 1, fp);

	node->father = parent;
	node->firstchild=loadfamilyfromfile(node,fp);
	node->nextchild=loadfamilyfromfile(parent,fp);

	return node;
}


//是否在这个区域内
bool isarea(int xx, int yy, int x, int y, int w, int h) {
	if (xx >= x && xx <= x + w && yy >= y && yy <= y + h)
		return true;
	else
		return false;
}

// 设置圆角按钮(带点击效果)
void button(int x, int y, int w, int h, const char text[], ExMessage msg) {
	if (isarea(msg.x, msg.y, x, y, w, h)) {
		Sleep(1);
		setfillcolor(BROWN);// 正常状态的颜色
	}
	else
		setfillcolor(RGB(0, 0, 0));// 按压状态的颜色(黑色)
	setbkmode(TRANSPARENT);
	fillroundrect(x, y, x + w, y + h, 10, 10);

	// 文字居中显示
	settextstyle(30, 0, "黑体");

	char text_[50] = "button";
	strcpy(text_, text);
	int tx = x + (w - textwidth(text_)) / 2;
	int ty = y + (h - textheight(text_)) / 2;

	outtextxy(tx, ty, text);
}

//drawbutton  表示放在这里就可以变色
void drawbutton(int x, int y, int w, int h, const char text[], ExMessage msg) {
	if (isarea(msg.x, msg.y, 450, 200, 650, 250) || isarea(msg.x, msg.y, 450, 260, 650, 310) ||
		isarea(msg.x, msg.y, 450, 320, 650, 370) || isarea(msg.x, msg.y, 450, 430, 650, 480) ||
		isarea(msg.x, msg.y, 450, 430, 650, 480))

		setfillcolor(RGB(200, 255, 198));
}

// 显示主菜单
void menu(ExMessage msg) {
	//打印按钮
	button(200, 200, 200, 50, "1. 创建家谱", msg);
	button(200, 260, 200, 50, "2. 查找成员", msg);
	button(200, 320, 200, 50, "3. 添加成员", msg);
	button(200, 380, 200, 50, "4. 修改成员", msg);
	button(600, 200, 200, 50, "5. 显示家谱", msg);
	button(600, 260, 200, 50, "6. 删除成员", msg);
	button(600, 320, 200, 50, "7. 保存文件", msg);
	button(600, 380, 200, 50, "0. 退出系统", msg);
}


//主界面UI
void mainUI() {
	ExMessage msg;

	//画了个家谱管理系统
	int x = 100, y = 20, xx = 900, yy = 120;
	fillroundrect(x, y, xx, yy, 10, 10);
	settextstyle(40, 0, "宋体");
	char text[] = "家谱管理系统";

	int tx = x + (xx - x - textwidth(text)) / 2;
	int ty = y + (yy - y - textheight(text)) / 2;

	outtextxy(tx, ty, text);

	BeginBatchDraw();
	if (peekmessage(&msg, EM_MOUSE | EX_DBLCLKS)) {
		menu(msg);
		switch (msg.message)
		{
		case WM_LBUTTONDOWN:
		case WM_RBUTTONDOWN:
			if (isarea(msg.x, msg.y, 200, 200, 200, 50)) {
				CurrentUI = UI::CreatefamilyUI;
			}
			if (isarea(msg.x, msg.y, 200, 260, 200, 50)) {
				CurrentUI = UI::FindNodeUI;
			}
			if (isarea(msg.x, msg.y, 200, 320, 200, 50)) {
				CurrentUI = UI::AddNodeUI;
			}
			if (isarea(msg.x, msg.y, 200, 380, 200, 50)) {
				CurrentUI = UI::ModifyUI;
			}
			if (isarea(msg.x, msg.y, 600, 200, 200, 50)) {
				CurrentUI = UI::PrintUI;
			}
			if (isarea(msg.x, msg.y, 600, 260, 200, 50)) {
				CurrentUI = UI::DeleteUI;
			}
			if (isarea(msg.x, msg.y, 600, 320, 200, 50)) {
				CurrentUI = UI::SaveUI;
			}
			if (isarea(msg.x, msg.y, 600, 380, 200, 50)) {
				CurrentUI = UI::Exit;
			}
			break;
		default:
			break;
		}
	}
}


//创建家谱图形化界面
void createfamilyUI() {

	setbkcolor(DARKGRAY);
	cleardevice();

	int x = 100, y = 20, xx = 900, yy = 120;
	fillroundrect(x, y, xx, yy, 10, 10);
	settextstyle(40, 0, "宋体");
	char text[] = "请输入你要创建的家族成员的信息";

	int tx = x + (xx - x - textwidth(text)) / 2;
	int ty = y + (yy - y - textheight(text)) / 2;

	outtextxy(tx, ty, text);

	EndBatchDraw();
	createfamily();
	CurrentUI = UI::MainUI;
}

// 查找成员界面
void findNodeUI() {
	setbkcolor(DARKGRAY);
	cleardevice();

	int x = 100, y = 20, xx = 900, yy = 120;
	fillroundrect(x, y, xx, yy, 10, 10);
	settextstyle(40, 0, "宋体");
	char text[] = "请输入你要查找的家族成员的信息";
	int tx = x + (xx - x - textwidth(text)) / 2;
	int ty = y + (yy - y - textheight(text)) / 2;

	outtextxy(tx, ty, text);

	FlushBatchDraw();

	int number;
	char input[100] = { 0 };
	// 1. 输入编号
	if (InputBox(input, 200, "输入编号", "请输入家族成员编号:")) {
		sscanf(input, "%d", &number);
	}

	CSTree p = findNode(root, number);
	if (p == NULL) {
		int result = MessageBox(NULL, "你应该是输入错误,请重新输入你要查找的成员编号", "确认", MB_YESNO);
		CurrentUI = UI::MainUI;
		return;
	}

	BeginBatchDraw();
	cleardevice();  // 清空之前的界面

	// 结果标题
	fillroundrect(x, y, xx, yy, 10, 10);
	char resultTitle[] = "查找结果";
	tx = x + (xx - x - textwidth(resultTitle)) / 2;
	outtextxy(tx, ty, resultTitle);

	// 显示结果
	settextstyle(24, 0, "宋体");
	if (p != NULL) {
		char info[100];
		sprintf(info, "编号: %d", p->pos.number);
		outtextxy(400, 150, info);

		sprintf(info, "姓名: %s", p->pos.name);
		outtextxy(400, 200, info);

		sprintf(info, "年龄: %d", p->pos.age);
		outtextxy(400, 250, info);

		sprintf(info, "性别: %s", p->pos.sex);
		outtextxy(400, 300, info);
	}
	else {
		outtextxy(350, 200, "未找到该成员!");
	}

	EndBatchDraw();
	// 简单返回提示
	settextcolor(YELLOW);
	outtextxy(350, 400, "点击任意位置返回主菜单");

	// 等待点击
	ExMessage msg;
	while (1) {
		if (peekmessage(&msg, EM_MOUSE) && msg.message == WM_LBUTTONDOWN) {
			CurrentUI = MainUI;
			break;
		}
		Sleep(10);
	}
}

// 添加成员界面
void addNodeUI() {
	setbkcolor(DARKGRAY);
	cleardevice();

	int x = 100, y = 20, xx = 900, yy = 120;
	fillroundrect(x, y, xx, yy, 10, 10);
	settextstyle(40, 0, "宋体");
	char text[] = "请输入你要添加的家族成员的信息";

	int tx = x + (xx - x - textwidth(text)) / 2;
	int ty = y + (yy - y - textheight(text)) / 2;

	outtextxy(tx, ty, text);

	FlushBatchDraw();
	BeginBatchDraw();
	addNode();

	EndBatchDraw();
	// 简单返回提示
	settextcolor(YELLOW);
	outtextxy(350, 400, "点击任意位置返回主菜单");

	// 等待点击
	ExMessage msg;
	while (1) {
		if (peekmessage(&msg, EM_MOUSE) && msg.message == WM_LBUTTONDOWN) {
			CurrentUI = MainUI;
			break;
		}
		Sleep(10);
	}
}

// 修改成员界面
void modifyUI() {
	setbkcolor(DARKGRAY);
	cleardevice();

	int x = 100, y = 20, xx = 900, yy = 120;
	fillroundrect(x, y, xx, yy, 10, 10);
	settextstyle(40, 0, "宋体");
	char text[] = "请输入你要修改的家族成员的信息";

	int tx = x + (xx - x - textwidth(text)) / 2;
	int ty = y + (yy - y - textheight(text)) / 2;

	outtextxy(tx, ty, text);

	FlushBatchDraw();
	BeginBatchDraw();
	modifyNode();

	EndBatchDraw();
	// 简单返回提示
	settextcolor(YELLOW);
	outtextxy(350, 400, "点击任意位置返回主菜单");

	// 等待点击
	ExMessage msg;
	while (1) {
		if (peekmessage(&msg, EM_MOUSE) && msg.message == WM_LBUTTONDOWN) {
			CurrentUI = MainUI;
			break;
		}
		Sleep(10);
	}
}

// 显示家谱界面
void printUI() {
	setbkcolor(DARKGRAY);
	cleardevice();

	// 绘制家谱树
	printFamilyTree(root);

	settextcolor(YELLOW);

	// 等待点击返回
	ExMessage msg;
	while (1) {
		if (peekmessage(&msg, EM_MOUSE) && msg.message == WM_LBUTTONDOWN) {
			CurrentUI = MainUI;
			break;
		}
		Sleep(10);
	}
}

// 删除成员界面
void deleteUI() {
	setbkcolor(DARKGRAY);
	cleardevice();

	int x = 100, y = 20, xx = 900, yy = 120;
	fillroundrect(x, y, xx, yy, 10, 10);
	settextstyle(40, 0, "宋体");
	char text[] = "请输入你要删除的家族成员的信息";

	int tx = x + (xx - x - textwidth(text)) / 2;
	int ty = y + (yy - y - textheight(text)) / 2;

	outtextxy(tx, ty, text);

	FlushBatchDraw();
	BeginBatchDraw();

	deleteFamily();

	EndBatchDraw();
	// 简单返回提示
	settextcolor(YELLOW);
	outtextxy(350, 400, "点击任意位置返回主菜单");

	// 等待点击
	ExMessage msg;
	while (1) {
		if (peekmessage(&msg, EM_MOUSE) && msg.message == WM_LBUTTONDOWN) {
			CurrentUI = MainUI;
			break;
		}
		Sleep(10);
	}
}



// 保存文件界面
void saveUI() {
	setbkcolor(DARKGRAY);
	cleardevice();

	int x = 100, y = 20, xx = 900, yy = 120;
	fillroundrect(x, y, xx, yy, 10, 10);
	settextstyle(40, 0, "宋体");
	char text[] = "保存文件界面";

	int tx = x + (xx - x - textwidth(text)) / 2;
	int ty = y + (yy - y - textheight(text)) / 2;

	outtextxy(tx, ty, text);

	FlushBatchDraw();
	BeginBatchDraw();

	savefamilyToFile(root);

	EndBatchDraw();
	// 简单返回提示
	settextcolor(YELLOW);
	outtextxy(350, 400, "点击任意位置返回主菜单");

	// 等待点击
	ExMessage msg;
	while (1) {
		if (peekmessage(&msg, EM_MOUSE) && msg.message == WM_LBUTTONDOWN) {
			CurrentUI = MainUI;
			break;
		}
		Sleep(10);
	}
	int result = MessageBox(NULL, "保存文件成功!", "确认", MB_YESNO);
}

int main() {
	FILE* fo = fopen("efe.dat", "rb");
	CSnode* load=loadfamilyfromfile(root,fo);
	root = load;

	//初始化图像界面
	initgraph(1000, 600, EW_SHOWCONSOLE);
	//图像界面颜色	淡蓝色背景
	setbkcolor(DARKGRAY);
	//清屏函数 清除屏幕上的所有内容
	cleardevice();

	CurrentUI = UI::MainUI;
	UI oldUI = UI::MainUI;

	while (CurrentUI != UI::Exit) {

		BeginBatchDraw();
		if (oldUI != CurrentUI) {
			oldUI = CurrentUI;
			//清屏函数 清除屏幕上的所有内容
			cleardevice();
		}
		switch (CurrentUI)
		{
		case MainUI:
			mainUI();
			break;
		case CreatefamilyUI:
			createfamilyUI();
			break;
		case FindNodeUI:
			findNodeUI();
			break;
		case AddNodeUI:
			addNodeUI();
			break;
		case ModifyUI:
			modifyUI();
			break;
		case PrintUI:
			printUI();
			break;
		case DeleteUI:
			deleteUI();
			break;
		case SaveUI:
			saveUI();
			break;
		case Exit:
			break;
		default:
			break;
		}
		EndBatchDraw();
	}
	//关闭图形模式的窗口
	closegraph();
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值