前段时间写了一个不完全的项目,虽然没有写完,但是还是很折磨人的
#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;
}