📄 student.cpp
字号:
// 增加一个节点到链表
// LPSTUDENT_INFO lpNode:新增加的节点
void AddToLink(LPSTUDENT_INFO lpNode)
{
if(!lpNode) return;
LPSTUDENT_INFO lpEnd;
if(!g_lpStudentHeader) // 原链表本来就为空
{
g_lpStudentHeader = lpNode;
g_lpStudentHeader->m_lpNext = NULL;
return;
}
lpEnd = g_lpStudentHeader;
while(lpEnd->m_lpNext) // 将lpEnd移动到最后一个节点
{
lpEnd = lpEnd->m_lpNext;
}
lpEnd->m_lpNext = lpNode;
lpNode->m_lpNext = NULL;
return;
}
// 从链表中删除一个节点
// LPSTUDENT_INFO lpNode:需要删除的节点
void DeleteFromLink(LPSTUDENT_INFO lpNode)
{
LPSTUDENT_INFO lpPrev = NULL;
if(!lpNode) return;
if(!g_lpStudentHeader) return;
if(lpNode == g_lpStudentHeader) // 要删除的本来就是头节点
{
g_lpStudentHeader = g_lpStudentHeader->m_lpNext;
free(lpNode);
return;
}
// 删除的不是头节点,则需要查找节点
lpPrev = g_lpStudentHeader;
while(lpPrev->m_lpNext != NULL)
{
if(lpPrev->m_lpNext == lpNode)
break;
lpPrev = lpPrev->m_lpNext;
}
if(!lpPrev->m_lpNext) return;
lpPrev->m_lpNext = lpNode->m_lpNext;
free(lpNode);
}
// 查找节点
// TCHAR *szKey:查找的依据
// BOOL bFlag:如果为TRUE,则按照学号查找,否则按照姓名查找
// 返回值:如果正确找到,则返回该节点地址
LPSTUDENT_INFO SearchLink(TCHAR *szKey, BOOL bFlag)
{
LPSTUDENT_INFO lpTmp = NULL;
int nRet = 0;
if(!g_lpStudentHeader) return NULL;
lpTmp = g_lpStudentHeader;
while(lpTmp != NULL)
{
if(bFlag) nRet = strcmp(szKey, lpTmp->m_szNumber);
else nRet = strcmp(szKey, lpTmp->m_szName);
if(!nRet) break; // 已经找到
lpTmp = lpTmp->m_lpNext;
}
return lpTmp;
}
// 清空链表
void ClearLink(void)
{
LPSTUDENT_INFO lpTmp = NULL;
lpTmp = g_lpStudentHeader;
while(lpTmp != NULL)
{
g_lpStudentHeader = g_lpStudentHeader->m_lpNext;
free(lpTmp);
lpTmp = g_lpStudentHeader;
}
g_lpStudentHeader = NULL;
return;
}
// 将链表保存到文件
// 如果保存失败,则返回FALSE
BOOL SaveLinkToFile(void)
{
FILE *fp = NULL;
int nRet = 0;
LPSTUDENT_INFO lpTmp = NULL;
if(!strlen(g_szFileName)) return FALSE;
fp = fopen(g_szFileName, "wb");
if(!fp) return FALSE; // 文件打开失败,不予保存
lpTmp = g_lpStudentHeader;
while(lpTmp)
{
nRet = fwrite(lpTmp, 1, sizeof(STUDENT_INFO), fp);
if(nRet != sizeof(STUDENT_INFO))
return FALSE;
lpTmp = lpTmp->m_lpNext;
}
return TRUE;
}
// 从文件读出链表
// 如果读取失败,则返回FALSE
BOOL ReadLinkFromFile(void)
{
FILE *fp = NULL;
int nRet = 0;
LPSTUDENT_INFO lpTmp, lpEnd;
ClearLink(); // 先清空原链表
if(!strlen(g_szFileName)) return FALSE;
fp = fopen(g_szFileName, "rb");
if(!fp) return FALSE; // 文件打开失败,不予读取
while(1)
{
lpTmp = (LPSTUDENT_INFO)malloc(sizeof(STUDENT_INFO));
nRet = fread(lpTmp, 1, sizeof(STUDENT_INFO), fp);
if(nRet == 0) break; // 读取结束
else if(nRet!=sizeof(STUDENT_INFO)) // 读取文件出错
return FALSE;
lpTmp->m_lpNext = NULL;
if(!g_lpStudentHeader)
{
lpEnd = g_lpStudentHeader = lpTmp;
}
else
{
lpEnd->m_lpNext = lpTmp;
lpEnd = lpEnd->m_lpNext;
}
}
fclose(fp);
return TRUE;
}
// 将链表以指定规则排序
// enum tagSortBy esOrderBy:指定按照哪个字段排序
// BOOL bAsc:为TRUE则升序,为FALSE则降序
void SortLinkBy(enum tagSortBy esOrderBy, BOOL bAsc)
{
LPSTUDENT_INFO lpTmp1 = NULL, lpTmp2 = NULL;
BOOL bFlag = FALSE;
// 使用选择法排序
for(lpTmp1=g_lpStudentHeader; lpTmp1!=NULL; lpTmp1=lpTmp1->m_lpNext)
{
for(lpTmp2=lpTmp1->m_lpNext; lpTmp2!=NULL; lpTmp2=lpTmp2->m_lpNext)
{
bFlag = FALSE;
switch(esOrderBy) // 看是以哪一种方式排序,从而决定比较哪两个字段
{
case NUMBER: // 按学号排序
bFlag = (strcmp(lpTmp1->m_szNumber, lpTmp2->m_szNumber) > 0);
break;
case NAME: // 按姓名排序
bFlag = (strcmp(lpTmp1->m_szName, lpTmp2->m_szName) > 0);
break;
case SEX: // 按性别排序
bFlag = (lpTmp1->m_bSex > lpTmp2->m_bSex);
break;
case AGE: // 按年龄排序
bFlag = (CompareAge(lpTmp1->m_dtBirthday,lpTmp2->m_dtBirthday) > 0);
break;
case CLASS: // 按班级排序
bFlag = (strcmp(lpTmp1->m_szClass, lpTmp2->m_szClass) > 0);
break;
case TELEPHONE: // 按电话号码排序
bFlag = (strcmp(lpTmp1->m_szTelephone, lpTmp2->m_szTelephone) > 0);
break;
case ADDRESS: // 按家庭住址排序
bFlag = (strcmp(lpTmp1->m_szAddress, lpTmp2->m_szAddress) > 0);
break;
default: return;
}
// bFlag决定是否交换,bAsc决定升序还是降序
if((bFlag && bAsc) || (!bFlag && !bAsc))
{
ExChangeNode(lpTmp1, lpTmp2); // 交换两个节点的内容
}
}
}
return;
}
// 交换两个节点
void ExChangeNode(LPSTUDENT_INFO lpNode1, LPSTUDENT_INFO lpNode2)
{
if(lpNode1==NULL || lpNode2==NULL) return;
LPSTUDENT_INFO lpNext1, lpNext2;
STUDENT_INFO tmp;
// 保存两个节点的“Next”指针先
lpNext1 = lpNode1->m_lpNext;
lpNext2 = lpNode2->m_lpNext;
// 将两个节点对换,使用中间变量tmp
memcpy(&tmp, lpNode1, sizeof(STUDENT_INFO));
memcpy(lpNode1, lpNode2, sizeof(STUDENT_INFO));
memcpy(lpNode2, &tmp, sizeof(STUDENT_INFO));
// 恢复两个节点的“Next”指针
lpNode1->m_lpNext = lpNext1;
lpNode2->m_lpNext = lpNext2;
return;
}
/////////////////////////////////////////////////////////////////
// 链表操作函数到此结束
/////////////////////////////////////////////////////////////////
// 设置文件是否保存
void SetSaveFlag(BOOL bFlag)
{
TCHAR szTitle[MAX_STRING] = "\0";
g_bIsSaved = bFlag;
strcpy(szTitle, "思远教育中心 - ");
if(strlen(g_szFileName))
{
strcat(szTitle, g_szFileName);
}
else
{
strcat(szTitle, "未命名");
}
if(!g_bIsSaved)
{
strcat(szTitle, " * ");
}
SetWindowText(g_hMainWnd, szTitle);
return;
}
// 显示Windows通用文件对话框,【保存】或者【打开】
// BOOL bSave:如果为TRUE,则显示【保存】对话框,如果为FALSE,则显示【打开】对话框
// 函数如果返回,则返回值为文件完整路径
TCHAR *CommFileDlg(BOOL bSave)
{
static TCHAR szFilePath[MAX_STRING] = "StudentInfo1.dat\0";
OPENFILENAME ofn;
// 过滤器字符串
TCHAR szFilter[] = "学生信息文件(*.MAP)\0*.dat\0"
"所有文件(*.*)\0*.*\0\0";
TCHAR szFileTitle[MAX_STRING] = "\0";
TCHAR szCurDir[MAX_STRING] = "\0";
BOOL bRet = FALSE;
GetCurrentDirectory(MAX_STRING, szCurDir); // 得到当前应用程序目录
memset(&ofn, 0, sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME); // 结构体的大小
ofn.hwndOwner = g_hMainWnd; // 弹出的对话框属于哪个窗口
ofn.hInstance = g_hAppInst; // 当前应用程序实例
ofn.lpstrFilter = szFilter; // 过滤器字符串
ofn.lpstrCustomFilter = NULL; // 额外的过滤器,不需要
ofn.nMaxCustFilter = 0; // 由于不需要额外过滤器,所以直接设置为0
ofn.nFilterIndex = 0; // 默认过滤器为第几项
ofn.lpstrFile = szFilePath; // 用来盛装选择的文件完整路径名
ofn.nMaxFile = MAX_STRING; // 上一个字段szFilePath的最大长度
ofn.lpstrFileTitle = szFileTitle; // 默认到编辑框中的文本
ofn.nMaxFileTitle = MAX_STRING; // 上一个字段szFileTitle的最大长度
ofn.lpstrInitialDir = szCurDir; // 初始化路径,通常就是NULL
if(bSave) ofn.lpstrTitle = "打开学生信息文件";
else ofn.lpstrTitle = "保存学生信息"; // 弹出对话框的标题栏上面的文本
//OFN_ENABLESIZING:对话框允许使用鼠标拖大拖小
//OFN_EXPLORER:对话框的左侧具有导航栏
//OFN_OVERWRITEPROMPT:如果是工作是“打开文件以保存”,则提示是否覆盖原文件
ofn.Flags = OFN_ENABLESIZING | OFN_EXPLORER | OFN_OVERWRITEPROMPT;
ofn.nFileOffset = 0; // 文件名在文件完整路径中的位置
ofn.nFileExtension = 0; // 文件后缀名在文件完整路径中的位置
ofn.lpstrDefExt = NULL; // 文件默认后缀名
ofn.lCustData = 0; // 用户自定义数据,这里不需要
ofn.lpTemplateName = NULL; // 当需要使用模板对话框的时候,可以指定一个对话框模板
// 显示【打开/保存】对话框
if(bSave)
bRet = GetSaveFileName(&ofn); // 显示【保存文件】对话框
else
bRet = GetOpenFileName(&ofn); // 显示【打开文件】对话框
if(!bRet) return NULL;
return szFilePath;
}
// 比较两个学生的年龄
// 返回值:如果dt1年龄比dt2大,则返回1
// 如果dt1年龄比dt2小,则返回-1
// 如果两人相同年龄, 则返回0
int CompareAge(DATE dt1, DATE dt2)
{
if(dt1.m_nYear < dt2.m_nYear)
return 1;
else if(dt1.m_nYear > dt2.m_nYear)
return -1;
else // 两人年份相同
{
if(dt1.m_nMonth < dt2.m_nMonth)
return 1;
else if(dt1.m_nMonth > dt2.m_nMonth)
return -1;
else // 年份和月份都相同
{
if(dt1.m_nDay < dt2.m_nDay)
return 1;
else if(dt1.m_nDay > dt2.m_nDay)
return -1;
else return 0; // 同年同月同日出生
}
}
return 0;
}
// 【添加新学生】对话框回调函数,此函数可以用来实现【修改学生信息】
LRESULT CALLBACK NewStuDlgProc(HWND hDlgWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static LPSTUDENT_INFO lpOrgStu = NULL;
switch (message)
{
case WM_INITDIALOG:
HWND hCtrlWnd;
int x;
TCHAR szText[MAX_STRING];
// 设置“性别”单选框
CheckRadioButton(hDlgWnd, IDC_RADIO_MALE, IDC_RADIO_FEMALE, IDC_RADIO_MALE);
hCtrlWnd = GetDlgItem(hDlgWnd, IDC_EDIT_NAME);
SendMessage(hCtrlWnd, EM_LIMITTEXT, 7, 0); // 设置“姓名”编辑框字符个数上限
hCtrlWnd = GetDlgItem(hDlgWnd, IDC_EDIT_NUMBER);
SendMessage(hCtrlWnd, EM_LIMITTEXT, 7, 0); // 设置“学号”编辑框字符个数上限
hCtrlWnd = GetDlgItem(hDlgWnd, IDC_EDIT_TEL);
SendMessage(hCtrlWnd, EM_LIMITTEXT, 7, 0); // 设置“联系电话”编辑框字符个数上限
hCtrlWnd = GetDlgItem(hDlgWnd, IDC_EDIT_ADDRESS);
SendMessage(hCtrlWnd, EM_LIMITTEXT, 48, 0); // 设置“家庭住址”编辑框字符个数上限
hCtrlWnd = GetDlgItem(hDlgWnd, IDC_COMBO_YEAR); // 设置“年份”下拉框中的数据
for(x=1900; x<2050; x++) // 最老年份为1900年,最年轻的年份为2050年
{
sprintf(szText, "%04d", x);
SendMessage(hCtrlWnd, CB_ADDSTRING, 0, (LPARAM)szText);
}
SendMessage(hCtrlWnd, CB_SETCURSEL, 76, 0); // 设置当前默认值为1976年
hCtrlWnd = GetDlgItem(hDlgWnd, IDC_COMBO_MONTH);// 设置“月份”下拉框中的数据
for(x=1; x<=12; x++) // 全年一共12个月份
{
sprintf(szText, "%02d", x);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -