前言
随笔之作,希望通过写文章的方式加深自己对于C++知识架构和设计过程中出现的一些Bug的印象,如有错误,多谢指正。
一、系统设计功能:
-
实现账号登陆界面。(例如:使用用户名和密码来进入界面。如果输入的用户名和密码有一项为空或者是输入的用户名和密码是错误的,则不能进入系统)
用户名:可以是学生名字也可以是学生个人学号。
-
实现任意添加学生的信息。(例如:添加学生的个人学号,姓名,性别,出生日期。专业,年级。添加记录时,要求学号要唯一。输入不允许为空,并且有提示功能;如果输入的时候有一项为空,则提示输入相关的信息。如果添加了重复的学号,这提示学号添加重复并且取消添加)。
-
实现删除学生的信息。(例如:实现对已添加的学生信息进行删除。如果当前系统中没有相应的记录,则提示“记录为空!”并返回操作。)
其中删除有两种方式:
第一种删除方式是直接在系统主页面选定单选框,直接“删除”
第二种删除方式是按“删除”,在查询窗口查询学生信息进行删除
(系统实现自动判断删除方式)
-
实现查询学生的信息。(例如:可根据学号或姓名等信息对已添加的学生信息进行查询,如果未找到,给出相应的提示信息,如果找到,则显示相应的记录信息)。
可以实现学号查询和姓名查询(至少要输入一个,否则将提示“请输入所需要查询的学生信息”)
-
实现编辑学生的信息。可根据查询结果对相应的记录进行修改。(例如:修改时注意学号的唯一性,包括编辑学生的个人学号,姓名,性别,专业,年级,出生日期。输入不允许为空,并且有提示功能,如果输入的时候有一项为空则提示输入相关的信息)。
编辑功能可以在系统主界面通过系统交互(双击学生信息,自动弹出修改窗口)进行修改,同时也可以通过选定单选框按“修改”进行修改(可以选中多个进行同时修改)
-
实现学生的信息保存功能。(例如:可将学生的信息存入文件中,存入方式任意(建立文件筛选格式)。保存学生信息包括学生个人学号,姓名,性别,专业,年级,出生日期)。
-
实现学生的信息导入功能。
-
实现注销功能。(例如:注销当前用户后,返回登陆界面)
在最后我添加了一个事件处理程序(NM-DNLCLK)来实现系统的用户交互,以至于可以在系统主界面直接双击学生信息既可以实现修改
二、对应板块
1.登陆板块
代码如下:
void CStudentControlManageDlg::OnBnClickedButton1Lgn() //登陆按钮
{
// TODO: 在此添加控件通知处理程序代码
CString sun;
CString spwd; // 创造两个字符串变量来接受用户输入的信息(用户名和密码等)
GetDlgItemText(IDC_EDIT2_UNAME, sun); // 返回用户名
GetDlgItemText(IDC_EDIT3_PWD, spwd); // 返回密码
/* 判断输入的用户名与密码是否正确
使用用户名(可以是学号,也可以是名字)和密码(唯一)相匹配实现登陆
如果其中一项为空或者错误都不可加入系统主页面,并且返回提示信息
*/
if (sun.IsEmpty())
{
MessageBox("用户名不能为空!");
return;
}
if (spwd.IsEmpty())
{
MessageBox("密码不能为空!");
return;
}
BOOL isSuccess = (!sun.CompareNoCase(_T("莫世冰")) && !spwd.CompareNoCase(_T("123456"))) || (!sun.CompareNoCase(_T("201934410316")) &&
!spwd.CompareNoCase(_T("123456"))); // 注意取反语句
// isSuccess = TRUE; //开发过程使用此语句,实现直接登陆
if (isSuccess)
{
ShowWindow(SW_HIDE); // 隐藏登陆窗口,但是需要在关闭系统主窗口的时候同时把子窗口也关闭,进入SystemDlg进行编译,增加WM-CLOSE信息和OnInitDialogc()函数
// 创造一个对话框,以至于能够弹出系统主页面(注意要引入主页面“SystemDlg”的头文件)
SystemDlg Dlg;
Dlg.DoModal(); // 弹出主系统界面,利用DoModal()函数
}
else
{
MessageBox(_T("用户名或者密码错误"), _T("登陆失败")); // 返回提示信息
}
}
2.系统主页面相应功能
代码如下:
void SystemDlg::OnClose()
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CDialog* dplg = (CDialog*)AfxGetMainWnd(); // 获得子窗口的指针
dplg->DestroyWindow(); // 利用指针是操作子窗口(自我销毁)
CDialogEx::OnClose();
}
// 在程序初始化的时候自动执行的函数
BOOL SystemDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// TODO: 在此添加额外的初始化
Student_list.SetExtendedStyle(LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT|LVS_EX_CHECKBOXES|LVS_EX_FLATSB); // 扩展样式,整行选中加复选框
// 数据进行 “行列” 排序 和 表头设置
// 1. 表头设置(InsertColumn(下标,表头,向右对齐0,宽度))
Student_list.InsertColumn(0, _T("年级"), 0, 200);
Student_list.InsertColumn(1, _T("专业班级"), 0, 200);
Student_list.InsertColumn(2, _T("姓名"), 0, 200);
Student_list.InsertColumn(3, _T("个人学号"), 0, 200);
Student_list.InsertColumn(4, _T("性别"), 0, 200);
Student_list.InsertColumn(5, _T("出生日期"), 0, 200);
CString g, z, n, num, m, year;
for (int i = 0; i < 8; i++)
{
g.Format(_T("学生%d"), i);
z.Format(_T("专业班级%d"), i);
n.Format(_T("姓名%d"),i);
num.Format(_T("学号%d"),i);
m.Format(_T("男"));
year.Format(_T("2000.02.%d"), i);
Student_list.InsertItem(i, g);
Student_list.SetItemText(i, 1, z);
Student_list.SetItemText(i, 2, n);
Student_list.SetItemText(i, 3, num);
Student_list.SetItemText(i, 4, m);
Student_list.SetItemText(i, 5, year);
}
Student_list.InsertItem(8, "目前页面为");
Student_list.SetItemText(8, 1, "示范数据");
Student_list.SetItemText(8, 2, "请选择全选键");
Student_list.SetItemText(8, 3, "进行“删除”");
Student_list.SetItemText(8, 4, "然后打开你所需要的");
Student_list.SetItemText(8, 5, "班级信息");
return TRUE; // return TRUE unless you set the focus to a control
// 异常: OCX 属性页应返回 FALSE
}
// 全部选中功能
void SystemDlg::OnBnClickedButton1()
{
// TODO: 在此添加控件通知处理程序代码
for (int i = 0; i < Student_list.GetItemCount(); i++)
{
Student_list.SetCheck(i, TRUE);
}
}
// 实现反选功能
void SystemDlg::OnBnClickedButtonReverse()
{
// TODO: 在此添加控件通知处理程序代码
for (int i = 0; i < Student_list.GetItemCount(); i++)
{
Student_list.SetCheck(i, !Student_list.GetCheck(i));
}
}
// 增加功能的窗口
void SystemDlg::OnBnClickedButtonAdd()
{
// TODO: 在此添加控件通知处理程序代码
AddDlg dlg; // 创建对话框
if (IDCANCEL == dlg.DoModal()) // 弹出对话框
{
return;
}
/* TODO:可以在这个位置进行信息的判断,
1.学号要唯一
2.输入不允许为空
(并且要有提示功能,提示1.xxx不允许为空 2. 添加数据重复并取消添加)
*/
/*增加窗口的功能要增加新的学生信息,然后返回到系统主页面(主窗口)当中
因此应该要创建窗口之间的传递对象
*/
int nCount = Student_list.GetItemCount();
if (dlg.sClass.IsEmpty())
{
AfxMessageBox("年级不能为空!!!");
return;
}
if (dlg.sMajor.IsEmpty())
{
AfxMessageBox("专业班级不能为空");
return;
}
if (dlg.sName.IsEmpty())
{
AfxMessageBox("名字不能为空");
return;
}
if (dlg.sID.IsEmpty())
{
AfxMessageBox("学号不能为空");
return;
}
if (dlg.sSex.IsEmpty())
{
AfxMessageBox("性别不能为空");
return;
}
if (dlg.sBirth.IsEmpty())
{
AfxMessageBox("出生日期不能为空");
return;
}
// 判断学号是否唯一
for (int i = 0; i < nCount; i++)
{
if (dlg.sID == Student_list.GetItemText(i, 3))
{
AfxMessageBox("学号重复,请输入正确的学号");
return;
}
}
// 编辑信息
Student_list.InsertItem(nCount, dlg.sClass);
Student_list.SetItemText(nCount, 1, dlg.sMajor);
Student_list.SetItemText(nCount, 2, dlg.sName);
Student_list.SetItemText(nCount, 3, dlg.sID);
Student_list.SetItemText(nCount, 4, dlg.sSex);
Student_list.SetItemText(nCount, 5, dlg.sBirth);
}
// 删除功能
void SystemDlg::OnBnClickedButtonDelete()
{
// TODO: 在此添加控件通知处理程序代码
/*
删除功能
1. 实现对已添加的学生信息进行删除。如果当前系统中没有相应的记录,则提示为空,并且返回操作
即可在查询的基础上查询是否有相应信息
2. 同时也可以通过在界面直接选择单选框,然后点击删除
*/
int nCount = Student_list.GetItemCount();
int flag = 1;
for (int i = 0; i < nCount; i++) // 判断是否与单选框得选中,然后再进行删除方式的切换
{
if (Student_list.GetCheck(i) == 1)
{
flag = 0;
}
}
if (flag)
{
SystemDlg::OnBnClickedButtonFind();
for (int i = 0; i < Student_list.GetItemCount(); i++) // 遍历每一项,判断是否被选中
{
BOOL state = Student_list.GetCheck(i);
if (state)
{
Student_list.DeleteItem(i); // 删除选定的项目
i--; // 因为for循环的原因,会导致程序从1.3.5.7.9这样子去判断每一项的状态,因此让程序返回一项判断,实现每一个项目的一个一个判断
}
}
}
if (!flag)
{
for (int i = 0; i < Student_list.GetItemCount(); i++) // 遍历每一项,判断是否被选中
{
BOOL state = Student_list.GetCheck(i);
if (state)
{
Student_list.DeleteItem(i); // 删除选定的项目
i--; // 因为for循环的原因,会导致程序从1.3.5.7.9这样子去判断每一项的状态,因此让程序返回一项判断,实现每一个项目的一个一个判断
}
}
}
}
// 查询功能
void SystemDlg::OnBnClickedButtonFind()
{
// TODO: 在此添加控件通知处理程序代码
int nCount = Student_list.GetItemCount();
for (int i = 0; i < nCount; i++) // 清空上次所选项
{
// ((CButton*)GetDlgItem(IDC_RADIO))->SetCheck(0);
if (Student_list.GetCheck(i) == 1)
{
Student_list.SetCheck(i, 0);
}
}
FindDlg dlg;
if (IDCANCEL == dlg.DoModal()) // 弹出对话框
{
return;
}
if (dlg.fID == "" && dlg.fName == "")
{
AfxMessageBox("请输入所需要查询的学生信息!!!");
}
else
{
int uNum = 1;
for (int i = 0; i < nCount; i++) // 通过和文本比较,选定寻找信息
{
if ((Student_list.GetItemText(i, 3) == dlg.fID || Student_list.GetItemText(i, 2) == dlg.fName))
{
Student_list.SetCheck(i); // 避免了在用姓名查找时因为名字重复而导致漏选的情况
uNum = 0;
}
if (i == nCount-1)
{
if(uNum)
{
AfxMessageBox("未找到相应记录!!!");
}
}
}
}
}
// 修改功能
void SystemDlg::OnBnClickedButtonAlter()
{
// TODO: 在此添加控件通知处理程序代码
/*
修改时注意学号的唯一性,而且输入的内容不能为空,如果重复或者为空这给予相关体现
*/
for (int i = 0; i < Student_list.GetItemCount(); i++) // 遍历每一项,判断是否被选中
{
BOOL state = Student_list.GetCheck(i);
if (state)
{
AddDlg dlg;
if (IDCANCEL == dlg.DoModal()) // 弹出对话框
{
return;
}
if (dlg.sClass.IsEmpty())
{
AfxMessageBox("学号不能为空!!!");
return;
}
if (dlg.sMajor.IsEmpty())
{
AfxMessageBox("专业班级不能为空");
return;
}
if (dlg.sName.IsEmpty())
{
AfxMessageBox("名字不能为空");
return;
}
if (dlg.sID.IsEmpty())
{
AfxMessageBox("学号不能为空");
return;
}
if (dlg.sSex.IsEmpty())
{
AfxMessageBox("性别不能为空");
return;
}
if (dlg.sBirth.IsEmpty())
{
AfxMessageBox("出生日期不能为空");
return;
}
// 判断学号是否唯一
int nCount = Student_list.GetItemCount();
for (int i = 0; i < nCount; i++)
{
if (dlg.sID == Student_list.GetItemText(i, 3))
{
AfxMessageBox("学号重复,请输入正确的学号");
return;
}
}
// 对已有信息进行修改(编辑),即在选定的项上,因此不用用InestItem(),直接用SetItemText() 即可
Student_list.SetItemText(i, 0, dlg.sClass);
Student_list.SetItemText(i, 1, dlg.sMajor);
Student_list.SetItemText(i, 2, dlg.sName);
Student_list.SetItemText(i, 3, dlg.sID);
Student_list.SetItemText(i, 4, dlg.sSex);
Student_list.SetItemText(i, 5, dlg.sBirth);
}
}
}
// 保存文件按钮
void SystemDlg::OnBnClickedButtonSave()
{
// TODO: 在此添加控件通知处理程序代码
// 建立一个CFileDialog文件对象(对话框),再进行文件的读取,再做出相应的操作。但应该注意的是,“.txt”会报错,因为字符分字符集和多字节储存
// (对象状态,文件类型,文件名字,覆盖功能,文件格式过滤,文件指针(这里不需要,用(空)NULL代表))
CFileDialog fDlg(FALSE, ".txt", "saveData", OFN_OVERWRITEPROMPT, "文本文档(*.txt)|*.txt|保存的数据(*.dat)|*.dat|所有文件(*.*)|*.*||", NULL);
if (fDlg.DoModal() == IDOK) // 判断文件是否打开成功
{
CStdioFile file(fDlg.GetPathName(), CFile::modeWrite | CFile::modeCreate); // 创建一个操作文件的对象(所获取的文件路径,文件的读取方式,写与新建并写入)
for (int i = 0; i < Student_list.GetItemCount(); i++) // 实现每一行数据的保持,写入文件,并且以逗号隔开
{
CString cs=""; // 创建一个接受字符的空变量
for (int j = 0; j < 6; j++)
{
cs += Student_list.GetItemText(i, j) + "#";
if (j == 4)
{
cs += Student_list.GetItemText(i, 5) + "\n";
j = 6;
}
}
file.WriteString(cs); // 每一行写入一次
}
file.Close(); // 关闭文件流
}
}
// 打开文件按钮
void SystemDlg::OnBnClickedButtonOpen()
{
// TODO: 在此添加控件通知处理程序代码
// (对象状态,文件格式,文件名,因为打开操作没有覆盖操作,即用0代替,文件格式过滤,文件指针(无))
CFileDialog fDlg(TRUE, ".txt", "saveData", 0, "文本文档(*.txt)|*.txt|保存的数据(*.dat)|*.dat|所有文件(*.*)|*.*||", NULL);
if (fDlg.DoModal() == IDOK) // 判断文件是否打开成功
{
CStdioFile file(fDlg.GetPathName(), CFile::modeRead); // 创建文件对象,进行读取的操作
CString cs; // 创建一个从文件取字符串的变量
int i = 0;
while (file.ReadString(cs)) // 利用C++中的Find() Left() Right() Mid()函数进行截取
{
int x = cs.Find("#");
int x1 = x;
Student_list.InsertItem(i, cs.Left(x));
for (int j = 1; j < 5; j++)
{
int x2 = cs.Find("#", x1 + 1);
Student_list.SetItemText(i, j, cs.Mid(x1 + 1, x2 - x1 - 1));
x1 = x2;
if (j == 4)
{
Student_list.SetItemText(i, j + 1, cs.Right(cs.GetLength() - x1 - 1));
j++;
}
}
i++;
}
}
}
// 实现用户交互功能的函数
void SystemDlg::OnNMDblclkList1(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
*pResult = 0;
int i = pNMItemActivate->iItem;
AddDlg dlg;
if (IDCANCEL == dlg.DoModal()) // 弹出对话框
{
return;
}
if (dlg.sClass.IsEmpty())
{
AfxMessageBox("学号不能为空!!!");
return;
}
if (dlg.sMajor.IsEmpty())
{
AfxMessageBox("专业班级不能为空");
return;
}
if (dlg.sName.IsEmpty())
{
AfxMessageBox("名字不能为空");
return;
}
if (dlg.sID.IsEmpty())
{
AfxMessageBox("学号不能为空");
return;
}
if (dlg.sSex.IsEmpty())
{
AfxMessageBox("性别不能为空");
return;
}
if (dlg.sBirth.IsEmpty())
{
AfxMessageBox("出生日期不能为空");
return;
}
// 判断学号是否唯一
int nCount = Student_list.GetItemCount();
for (int i = 0; i < nCount; i++)
{
if (dlg.sID == Student_list.GetItemText(i, 3))
{
AfxMessageBox("学号重复,请输入正确的学号");
return;
}
}
Student_list.SetItemText(i, 0, dlg.sClass);
Student_list.SetItemText(i, 1, dlg.sMajor);
Student_list.SetItemText(i, 2, dlg.sName);
Student_list.SetItemText(i, 3, dlg.sID);
Student_list.SetItemText(i, 4, dlg.sSex);
Student_list.SetItemText(i, 5, dlg.sBirth);
}
// 注销按钮
void SystemDlg::OnBnClickedButtonEnd()
{
// TODO: 在此添加控件通知处理程序代码
CDialog::OnOK(); // 消掉子窗口
CStudentControlManageDlg dlg; // 弹出登陆页面
if (dlg.DoModal() != IDOK)
{
SystemDlg::OnClose(); // 实现关闭程序的功能
}
}
其中需要注意的几点有:
1.在从登陆窗口弹出系统主页面时,只是单纯地隐藏登陆窗口是不行的,因为程序在任务管理器仍然在运行,因此要利用指针指向登陆窗口,实现DestroyWindow()窗口的自己摧毁
2.在查询功能板块,再次选择查询功能时要实现数据单项框的全部取消(即取消选定)
3.在保存和打开文件利用CFileDialog fDlg()函数时,第一个“TURE”或者“FALSE”参数可能会报错,因为程序实现字符串保存时,默认为Unicode字符集,这时候我们只需改成多字节字符集即可(具体步骤:“文件属性”->“常规”->“字符集”->“多字节字符集”);
4.各种控件、窗口等的正确使用、相互引用等问题
总结
虽然是老掉牙的学生管理系统,但是在第一次的学习过程中,可谓是获益匪浅,同时也希望以此为记录,相信以后有机会回来写这个系统,我可以写的更好看,功能更加齐全。