📄 student.cpp
字号:
#include "stdafx.h"
#include "resource.h"
typedef struct tagDate
{
unsigned int m_nYear;
unsigned int m_nMonth;
unsigned int m_nDay;
}DATE, *LPDATE;
typedef struct tagStudentInfo
{
char m_szName[8]; // 姓名
char m_szNumber[8]; // 学号
int m_bSex; // 性别,TRUE为男,FALSE为女
DATE m_dtBirthday; // 出生年月日
char m_szClass[8]; // 班级
char m_szTelephone[10];// 电话
char m_szAddress[50]; // 家庭住址
struct tagStudentInfo *m_lpNext; // 下一个学生
}STUDENT_INFO, *LPSTUDENT_INFO;
// 枚举类型,定义一组枚举常量
enum tagSortBy{NUMBER=IDM_VIEW_NUMBER, NAME, SEX, AGE, CLASS, TELEPHONE, ADDRESS};
// 全局变量:
HINSTANCE g_hAppInst = NULL; // 全局变量,应用程序实例
HWND g_hMainWnd = NULL; // 全局变量,主窗口句柄
SIZE g_sInfoTextSize = {1280, 100}; // 窗口中显示的文本最大高度和宽度
LPSTUDENT_INFO g_lpStudentHeader = NULL; // 学生链表头指针
TCHAR g_szFileName[MAX_STRING] = "\0"; // 用来保存学生信息的文件名
BOOL g_bIsSaved = TRUE; // 文件是否已经保存
BOOL g_bOrderByAsc = TRUE; // 排序规则
UINT g_uOrderByField = NUMBER; // 排序字段
// 用户自定义函数:
// 一些回调函数:
LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM); // 主窗口回调函数
LRESULT CALLBACK AboutDlgProc(HWND, UINT, WPARAM, LPARAM); // 【关于】对话框回调函数
LRESULT CALLBACK NewStuDlgProc(HWND, UINT, WPARAM, LPARAM); // 【增加新学生】对话框回调函数
LRESULT CALLBACK DeleteDlgProc(HWND, UINT, WPARAM, LPARAM); // 【删除学生】对话框回调函数
// 主窗口消息响应函数:
void OnCreate(CREATESTRUCT *); // 响应WM_CREATE消息
void OnPaint(HDC); // 响应WM_PAINT消息
void OnCommand(WPARAM, LPARAM); // 响应WM_COMMAND消息
void OnClose(void); // 响应WM_CLOSE消息
void OnVScroll(UINT, UINT, HWND); // 响应垂直滚动条消息WM_VSCROLL
void OnHScroll(UINT, UINT, HWND); // 响应水平滚动条消息WM_HSCROLL
void OnSize(UINT, UINT); // 响应WM_SIZE消息函数,窗口大小发生改变
void OnRButtonUp(POINT, UINT); // 鼠标右键抬起消息WM_RBUTTONUP
void OnLButtonDblClk(POINT, UINT); // 鼠标左键双击消息WM_LBUTTONDBCLICK
BOOL OnFileSave(void); // 响应菜单【文件】->【保存】事件
BOOL OnFileSaveAs(void); // 响应菜单【文件】->【另存为】事件
void OnFileOpen(void); // 响应菜单【文件】->【打开】事件
void OnFileNew(void); // 响应菜单【文件】->【新建】事件
void OnViewNumber(void); // 响应菜单【查看】->【按学号排序】事件
void OnViewName(void); // 响应菜单【查看】->【按姓名排序】事件
void OnViewSex(void); // 响应菜单【查看】->【按性别排序】事件
void OnViewAge(void); // 响应菜单【查看】->【按年龄排序】事件
void OnViewClass(void); // 响应菜单【查看】->【按班级排序】事件
void OnViewTelephone(void); // 响应菜单【查看】->【按电话号码排序】事件
void OnViewAddress(void); // 响应菜单【查看】->【按家庭住址排序】事件
void OnToolAddNew(void); // 响应菜单【工具】->【增加学生】事件
void OnToolDelete(void); // 响应菜单【工具】->【删除学生】事件
void OnToolModify(void); // 响应菜单【工具】->【修改学生】事件
// 链表操作函数
void AddToLink(LPSTUDENT_INFO); // 增加一个节点到链表
void DeleteFromLink(LPSTUDENT_INFO); // 删除一个节点
LPSTUDENT_INFO SearchLink(TCHAR *, BOOL);// 查找节点
void ClearLink(void); // 清空链表
BOOL SaveLinkToFile(void); // 将链表保存到文件
BOOL ReadLinkFromFile(void); // 从文件读出链表
void SortLinkBy(enum tagSortBy, BOOL);// 将链表以指定规则排序
void ExChangeNode(LPSTUDENT_INFO, LPSTUDENT_INFO); // 交换两个节点
// 其他一些函数
void SetSaveFlag(BOOL); // 设置保存标志
void SaveQuestion(void); // 文件数据可能已经更改,询问是否需要保存
TCHAR *CommFileDlg(BOOL); // 显示Windows通用对话框,保存或者打开文件对话框
int CompareAge(DATE, DATE); // 比较两个个学生的年龄
void InitDateCombo(HWND); // 初始化【添加新学生】对话框上的日期下拉框
void InitScrollBar(SIZE, BOOL); // 初始化主窗口滚动条
LPSTUDENT_INFO GetNewStudentInfo(HWND, LPSTUDENT_INFO); // 得到新输入的或刚修改的学生信息
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg; // 消息结构体
HACCEL hAccelTable; // 加速键表资源句柄
WNDCLASSEX wcex; // 窗口类结构体
TCHAR szClass[MAX_STRING]; // 用来存放窗口类字符串
TCHAR szTitle[MAX_STRING]; // 用来存放窗口标题字符串
HWND hWnd; // 窗口句柄
g_hAppInst = hInstance;
// 从字符串资源中载入字符串
LoadString(hInstance, IDC_STUDENT, szClass, MAX_STRING);
// 开始注册窗口类
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wcex.lpfnWndProc = (WNDPROC)MainWndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_STUDENT);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = (LPCSTR)IDC_STUDENT;
wcex.lpszClassName = szClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
RegisterClassEx(&wcex); // 注册窗口类
// 从字符串资源中载入字符串
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_STRING);
// 创建窗口
hWnd = CreateWindow(szClass, szTitle, WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd) return 0;
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
// 载入加速键资源
hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_STUDENT);
// 主消息循环:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
UnregisterClass(szClass, hInstance); // 反注册窗口类
return msg.wParam;
}
// 主窗口回调函数:
LRESULT CALLBACK MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
g_hMainWnd = hWnd;
OnCreate((LPCREATESTRUCT)lParam);
break;
case WM_COMMAND:
OnCommand(wParam, lParam);
break;
case WM_PAINT:
PAINTSTRUCT ps;
HDC hdc;
hdc = BeginPaint(hWnd, &ps);
OnPaint(hdc);
EndPaint(hWnd, &ps);
break;
case WM_SIZE: // 当窗口大小发生改变的时候得到此消息
OnSize(LOWORD(lParam), HIWORD(lParam));
break;
case WM_VSCROLL: // 当垂直滚动条发生改变是发送此消息,比如拖动滚动条等
OnVScroll(LOWORD(wParam), HIWORD(wParam), NULL);
break;
case WM_HSCROLL: // 当水平滚动条发生改变是发送此消息,比如拖动滚动条等
OnHScroll(LOWORD(wParam), HIWORD(wParam), NULL);
break;
case WM_CLOSE:
OnClose();
break;
case WM_RBUTTONUP:
POINT pt1;
pt1.x = LOWORD(lParam);
pt1.y = HIWORD(lParam);
OnRButtonUp(pt1, wParam);
break;
case WM_LBUTTONDBLCLK:
POINT pt2;
pt2.x = LOWORD(lParam);
pt2.y = HIWORD(lParam);
OnLButtonDblClk(pt2, wParam);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
/////////////////////////////////////////////////////////////////
// 下面的所有函数都是主窗口消息响应函数
////////////////////////////////////////////////////////////////
// 响应WM_CREATE消息
void OnCreate(LPCREATESTRUCT lpCreateStruct)
{
HMENU hMenu;
ClearLink(); // 窗口刚刚创建,清除链表结构
SetSaveFlag(TRUE); // 没有信息,无所谓保存
// 设置【查看】菜单下的菜单项单选状况
hMenu = GetMenu(g_hMainWnd);
CheckMenuRadioItem(hMenu, IDM_VIEW_ASC, IDM_VIEW_DESC, IDM_VIEW_ASC, MF_BYCOMMAND);
CheckMenuRadioItem(hMenu, IDM_VIEW_NUMBER, IDM_VIEW_ADDRESS, IDM_VIEW_NUMBER, MF_BYCOMMAND);
g_bOrderByAsc = TRUE;
g_uOrderByField = NUMBER;
}
// 响应WM_COMMAND消息
void OnCommand(WPARAM wParam, LPARAM lParam)
{
int wmEvent, wmID;
HMENU hMenu = NULL;
wmID = LOWORD(wParam);
wmEvent = HIWORD(wParam);
switch(wmID)
{
case IDM_HELP_ABOUT: // 菜单【帮助->关于】项
DialogBox(g_hAppInst, (LPCTSTR)IDD_ABOUTBOX, g_hMainWnd, (DLGPROC)AboutDlgProc);
break;
case IDM_HELP_HELP: // 菜单【帮助->帮助】项
MessageBox(g_hMainWnd, "即将显示帮助", "消息", MB_OK);
break;
case IDM_FILE_SAVE: // 菜单【文件->保存】项
OnFileSave();
break;
case IDM_FILE_SAVEAS: // 菜单【文件->另存为】项
OnFileSaveAs();
break;
case IDM_FILE_NEW: // 菜单【文件->新建】项
OnFileNew();
break;
case IDM_FILE_OPEN: // 菜单【文件->打开】项
OnFileOpen();
break;
case IDM_FILE_EXIT: // 菜单【文件->退出】项
PostMessage(g_hMainWnd, WM_CLOSE, 0, 0);
break;
case IDM_VIEW_NAME: // 菜单【查看->按姓名排序】事件
case IDM_VIEW_NUMBER: // 菜单【查看->按学号排序】事件
case IDM_VIEW_SEX: // 菜单【查看->按性别排序】项
case IDM_VIEW_AGE: // 菜单【查看->按年龄排序】项
case IDM_VIEW_CLASS: // 菜单【查看->按班级排序】项
case IDM_VIEW_TELEPHONE:// 菜单【查看->按电话号码排序】项
case IDM_VIEW_ADDRESS: // 菜单【查看->按家庭住址排序】项
g_uOrderByField = wmID; // 将排序字段保存到全局变量
// 实现排序
SortLinkBy((enum tagSortBy)g_uOrderByField, g_bOrderByAsc);
// 设置菜单单选状态
hMenu = GetMenu(g_hMainWnd);
CheckMenuRadioItem(hMenu, IDM_VIEW_NUMBER, IDM_VIEW_ADDRESS, wmID, MF_BYCOMMAND);
InvalidateRect(g_hMainWnd, NULL, TRUE);
break;
case IDM_VIEW_ASC: // 菜单【查看->升序】项
case IDM_VIEW_DESC: // 菜单【查看->降序】项
g_bOrderByAsc = (wmID == IDM_VIEW_ASC); // 将排序规则保存到全局变量
// 实现排序
SortLinkBy((enum tagSortBy)g_uOrderByField, g_bOrderByAsc);
// 设置菜单单选状态
hMenu = GetMenu(g_hMainWnd);
CheckMenuRadioItem(hMenu, IDM_VIEW_ASC, IDM_VIEW_DESC, wmID, MF_BYCOMMAND);
InvalidateRect(g_hMainWnd, NULL, TRUE);
break;
case IDM_VIEW_FRESH: // 菜单【查看】->【刷新】事件
InvalidateRect(g_hMainWnd, NULL, TRUE);
break;
case IDM_TOOL_ADDNEW: // 菜单【工具】->【增加新学生】事件
OnToolAddNew();
break;
case IDM_TOOL_DELETE: // 菜单【工具】->【删除学生】事件
OnToolDelete();
break;
case IDM_TOOL_MODIFY: // 菜单【工具】->【修改学生】事件
OnToolModify();
break;
default:
DefWindowProc(g_hMainWnd, WM_COMMAND, wParam, lParam);
break;
}
return;
}
// 响应消息WM_PAINT,将学生信息显示到屏幕
void OnPaint(HDC hMainDC)
{
TCHAR szTitle[MAX_STRING] = "学号 " // 显示列表的标题
"姓名 "
"性别 "
"出生年月 "
"班级 "
"联系电话 "
"家庭住址";
TCHAR szSex[4] = "男";
TCHAR szBirthday[20] = "8888年88月88日";
HFONT hFont = NULL, hOldFont = NULL;
LPSTUDENT_INFO lpTmp = NULL;
RECT rt;
int xOrg, yOrg, yPos = 0;
GetClientRect(g_hMainWnd, &rt); // 得到客户区大小
// 注:如果本窗口没有滚动条,则下面3行代码可以去掉
xOrg = -GetScrollPos(g_hMainWnd, SB_HORZ); // 得到水平滚动条的位置
yOrg = -GetScrollPos(g_hMainWnd, SB_VERT); // 得到垂直滚动条的位置
SetViewportOrgEx(hMainDC, xOrg, yOrg, NULL); // 设置视口起点
// 创建一个字体,以后的文字输出按照此字体输出
// 如果不使用自创字体,则可能导致输出难以对齐,输出不够美观
hFont = CreateFont(14, // 字体高度16像素
7, // 字体宽度16像素
0, // 字体不倾斜
0, // 行不倾斜
FW_SEMIBOLD, // 字体适当加粗
FALSE, // 字体不斜体
FALSE, // 字体不加下划线
FALSE, // 字体不加删除线(中划线)
ANSI_CHARSET, // ANSI字符
OUT_DEFAULT_PRECIS, // 缺省输出精度
CLIP_DEFAULT_PRECIS, // 缺省输出精度
DEFAULT_QUALITY, // 缺省输出质量
DEFAULT_PITCH, // 缺省字符间距
NULL); // 使用默认字体名
// 将字体选入设备上下文
hOldFont = (HFONT)SelectObject(hMainDC, hFont);
// 显示表头信息
SetTextColor(hMainDC, RGB(255,50,50));
TextOut(hMainDC, 0, yPos, szTitle, strlen(szTitle));
MoveToEx(hMainDC, 0, 20, NULL);
LineTo(hMainDC, 1280, 20);
MoveToEx(hMainDC, 0, 22, NULL);
LineTo(hMainDC, 1280, 22);
// 开始显示学生信息
lpTmp = g_lpStudentHeader;
yPos = 30;
SetTextColor(hMainDC, RGB(50,50,255));
while(lpTmp != NULL)
{
// 初始化“性别”字段
if(lpTmp->m_bSex) sprintf(szSex, "男");
else sprintf(szSex, "女");
// 初始化“出生年月”字段
sprintf(szBirthday, "%04d年%02d月%02d日",
lpTmp->m_dtBirthday.m_nYear, lpTmp->m_dtBirthday.m_nMonth, lpTmp->m_dtBirthday.m_nDay);
// 显示学生学号
TextOut(hMainDC, 0, yPos, lpTmp->m_szNumber, strlen(lpTmp->m_szNumber));
// 显示学生姓名
TextOut(hMainDC, 100, yPos, lpTmp->m_szName, strlen(lpTmp->m_szName));
// 显示学生性别
TextOut(hMainDC, 200, yPos, szSex, strlen(szSex));
// 显示学生出生年月日
TextOut(hMainDC, 230, yPos, szBirthday, strlen(szBirthday));
// 显示学生班级号
TextOut(hMainDC, 355, yPos, lpTmp->m_szClass, strlen(lpTmp->m_szClass));
// 显示学生电话号码
TextOut(hMainDC, 470, yPos, lpTmp->m_szTelephone, strlen(lpTmp->m_szTelephone));
// 显示学生家庭住址
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -