[课堂学习]多线程课程学习(一)- MFC - 学生健康体温上报系统

MFC - 学生健康体温上报系统

关于MFC的学习请移步:http://www.jizhuomi.com/software/257.html
非常感谢鸡啄米团队为MFC网络教学做出的贡献!

垃圾话

还是我,网课上了一月多,桌游的开发暂缓了很久。。天天被学校的微信小程序催着上报健康情况,因此正好拿来做成多核编程课的作业。。果然艺术来源自生活啊

需求分析

  1. 提交业务
  2. 查询业务
  3. 导入业务(方便调试)

1. 提交业务
要求能将用户输入的姓名、学号、体温数据打包写入txt文档中

2. 查询业务
要求能根据用户输入的学号,查询txt文档中是否有此人的记录并显示,且需要通过控制进度条展示查询进度

3. 导入业务
要求能通过txt批量提交学生信息

框架设计

  1. 设计学生类Student
  2. 设计提交线程SubmitThread
  3. 设计查询线程SearchThread
  4. 设计进度条控制线程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;
}

总结

  1. 学习了CStdioFile类的使用
  2. 学习了MFC的消息映射,解决了一些问题,例如:
    https://blog.csdn.net/junbopengpeng/article/details/38392495
  3. 学习了互斥量的处理

好了我们下期,额,也许是下月,总之——再见!

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值