MFC - 学生健康体温上报系统
关于MFC的学习请移步:http://www.jizhuomi.com/software/257.html
非常感谢鸡啄米团队为MFC网络教学做出的贡献!
垃圾话
还是我,网课上了一月多,桌游的开发暂缓了很久。。天天被学校的微信小程序催着上报健康情况,因此正好拿来做成多核编程课的作业。。果然艺术来源自生活啊
需求分析
- 提交业务
- 查询业务
- 导入业务(方便调试)
1. 提交业务
要求能将用户输入的姓名、学号、体温数据打包写入txt文档中
2. 查询业务
要求能根据用户输入的学号,查询txt文档中是否有此人的记录并显示,且需要通过控制进度条展示查询进度
3. 导入业务
要求能通过txt批量提交学生信息
框架设计
- 设计学生类Student
- 设计提交线程SubmitThread
- 设计查询线程SearchThread
- 设计进度条控制线程ProgressThread
代码展示
0. 交互界面设计
为各个EDIT输入框分别添加了CString stu_name、CString stu_number、double stu_temp、int stu_cnt变量,为进度条添加了控件CProgressCtrl progress_ctrl
1. 学生类
class Student
{
public:
CString name;
CString number;
double temp;
Student() :name(_T("")), number(_T("")), temp(0) {}
Student(CString na, CString nu, double te) :name(na), number(nu), temp(te) {}
// 通过CString初始化,便于从txt中读取,还原student对象
Student(CString pack)
{
int a1 = pack.Find(_T(' '), 0);
int a2 = pack.Find(_T(' '), a1 + 1);
int a3 = pack.GetLength();
number = pack.Left(a1);
name = pack.Mid(a1 + 1, a2 - a1 - 1);
temp = _ttof(pack.Right(a3 - a2 - 1));
}
// 打包函数,便于写入txt文档,将学生的三个信息打包为一个CString
CString PackAsCString(int style=0)
{
CString str;
str.Format(_T("%.2lf"), temp);
if(style==0)
str = number + _T(" ") + name + _T(" ") + str + _T("\n");
else
str = _T("学号: ") + number
+ _T("\r\n姓名:") + name
+ _T("\r\n体温:") + str + _T("\r\n");
return str;
}
};
2. 设计提交线程SubmitThread(同时实现了提交业务和导入业务)
全局变量,用于线程间的同步
int file_able = 1; // 协调各个使用test.txt的线程,防止冲突
int file_progress = 0; // 查询进度:已查询到文档中第几人
UINT SubmitThread(LPVOID lParam);
UINT SearchThread(LPVOID lParam);
UINT ProgressThread(LPVOID lParam);
所谓的导入就是提前在txt中按格式写好信息,然后报告给程序里面有多少人的信息罢了。。
// 提交按钮回调函数
void CRegisterDlg::OnBnClickedSubmitButton()
{
// TODO: 在此添加控件通知处理程序代码
if (file_able)
{
UpdateData(TRUE);
if (stu_name.GetLength() == 0)
{
MessageBox(_T("没有输入姓名,提交失败"));
}
else if (_tcscmp(stu_name, _T("#导入")) == 0)
{
CString str;
str.Format(_T("成功导入%d人"), stu_cnt);
MessageBox(str);
}
else if (stu_number.GetLength() == 0)
{
MessageBox(_T("没有输入学号,提交失败"));
}
else
{
file_able = 0;
stu_cnt++;
UpdateData(FALSE);
// 添加线程
AfxBeginThread(SubmitThread, this);
}
}
else
{
MessageBox(_T("文件正在被占用,请稍后..."));
}
}
UINT SubmitThread(LPVOID lParam)
{
if (lParam == NULL)
return -1;
CRegisterDlg* pDlg = (CRegisterDlg*)lParam;
Student stu = Student(pDlg->stu_name,pDlg->stu_number,pDlg->stu_temp);
CString str = stu.PackAsCString();
CStdioFile cFile;
LPCTSTR path = _T("test.txt");
cFile.Open(path, CFile::modeReadWrite | CFile::modeNoTruncate | CFile::modeCreate);
// 写入内容, 定位到文件尾部
cFile.SeekToEnd();
cFile.WriteString(str);
cFile.Close();
pDlg->MessageBox(_T("提交成功"));
file_able = 1;
return 0;
}
3. 设计查询线程SearchThread
// 查询按钮回调函数
void CRegisterDlg::OnBnClickedSearchButton()
{
// TODO: 在此添加控件通知处理程序代码
if (file_able)
{
UpdateData(TRUE);
if (stu_number.GetLength() == 0)
{
MessageBox(_T("没有输入学号,查询失败"));
}
else
{
file_able = 0;
file_progress = 0;
progress_ctrl.SetPos(0);
// 添加线程
AfxBeginThread(SearchThread, this);
AfxBeginThread(ProgressThread, this);
}
}
else
{
MessageBox(_T("文件正在被占用,请稍后..."));
}
}
UINT SearchThread(LPVOID lParam)
{
if (lParam == NULL)
return -1;
CRegisterDlg* pDlg = (CRegisterDlg*)lParam;
CStdioFile cFile;
LPCTSTR path = _T("test.txt");
if (!PathFileExists(path))
{
pDlg->MessageBox(_T("查询失败,没有任何学生提交过健康记录"));
file_able = 1;
return 0;
}
cFile.Open(path, CFile::modeRead);
cFile.SeekToBegin();
CString number = pDlg->stu_number;
CString str;
CString success_msg = _T("查询成功\r\n");
CString fail_msg = _T("查询结果,查无此人\r\n");
bool success = false;
while (cFile.ReadString(str))
{
Student stu = Student(str);
if (_tcscmp(stu.number, number) == 0)
{
// 进度条快进到100%
file_progress = pDlg->stu_cnt;
str = stu.PackAsCString(1);
if (stu.temp > 37.3)
{
str = success_msg + str
+ _T("该学生体温过高,建议联系当地发热门诊就诊\r\n");
}
else if (stu.temp < 35)
{
str = success_msg + str
+ _T("该学生体温过低,可能只是个恶作剧\r\n");
}
else
{
str = success_msg + str
+ _T("该学生体温正常\r\n");
}
pDlg->MessageBox(str);
success = true;
break;
}
else
{
file_progress++;
}
// 这里延时一会,好让用户加钱优化
Sleep(500);
};
if(!success)
pDlg->MessageBox(fail_msg);
cFile.Close();
file_able = 1;
return 0;
}
4. 设计进度条控制线程ProgressThread
UINT ProgressThread(LPVOID lParam)
{
if (lParam == NULL)
return -1;
CRegisterDlg* pDlg = (CRegisterDlg*)lParam;
int file_progress_top = pDlg->stu_cnt;
while (file_progress < file_progress_top)
{
int pos = (int)(100.0 * file_progress / file_progress_top);
pDlg->progress_ctrl.SetPos(pos);
}
pDlg->progress_ctrl.SetPos(100);
return 0;
}
总结
- 学习了CStdioFile类的使用
- 学习了MFC的消息映射,解决了一些问题,例如:
https://blog.csdn.net/junbopengpeng/article/details/38392495
- 学习了互斥量的处理
好了我们下期,额,也许是下月,总之——再见!