MFC案例:利用SetTimer函数编写一个“计时器”程序

一、希望达成效果

利用基于对话框的MFC项目,做一个一方面能够显示当前时间;另一方面在点击开始按钮时进行读秒计时,计时结果动态显示,当点击结束时读秒结束并保持最后结果。

二、编程步骤及相关代码、注释

1、启动VS->创建新项目->MFC应用-项目名称:MFCtimer->创建->在应用程序类型中选择:基于对话框->完成。启动后,将"TODO:"、"确定"、"取消"等删去。

2、从工具箱先拖入一些静态文本框,用于显示提示文字,选择这些控件,右键属性后更改ID、右键添加变量后添加变量。具体包括:

属性ID: IDC_CTIME 变量名: m_CTIME 显示:当前时间("当前时间"在更改写入)

属性ID: IDC_YEAR 变量名: m_YEAR 显示:年

属性ID: IDC_MONTH 变量名: m_MONTH 显示:月

属性ID: IDC_DAY 变量名: m_DAY 显示:日

属性ID: IDC_HOUR 变量名: m_HOUR 显示:时

属性ID: IDC_MINUTE 变量名: m_MINUTE 显示:分

属性ID:IDC_TITLE 显示:计时器

上面IDC_TITLE以及下面介绍的一些控件,没有添加变量名,目的是为了在程序中介绍如何使用变量,以及仅使用ID调用成员函数的方法;在这个程序中,加不加变量名无所谓。

3、从工具箱拖入文本编辑框:5个用于显示当前时间;2个用于显示读秒。使用与静态文本框相似的方法,为这些文本编辑框更改ID。

属性ID:IDC_SHOW_YEAR 显示:年(不是"年"字,指2024,下同)

属性ID:IDC_SHOW_MONTH 显示:月

属性ID:IDC_SHOW_DAY 显示:日

属性ID:IDC_SHOW_HOUR 显示:时

属性ID:IDC_SHOW_MINUTE 显示:分

属性ID:IDC_SHOW_TIMER1 变量名:m_showTimer1 显示:读秒 注:这里只有它加了变量名

属性ID:IDC_SHOW_TIMER2 显示:读秒(化成"__分__秒"格式)

4、拖入两个按钮,ID不改了,就用缺省的:IDC_BUTTON1、IDC_BUTTON2。右键这两个按钮,选择属性,ID不改了,但要把文字描述改成"开始计时"、"结束及时"。并分别给这两个按钮添加处理程序void CMFCtimerDlg::OnBnClickedButton1()、void CMFCtimerDlg :: OnBnClickedButton2(),后边要用到。

5、至此,除了已经自动生成的代码,我们还没有写过代码。下面开始添加代码工作:

a.在MFCtimerDlg.h中声明几个变量:

cpp 复制代码
public:
         CFont cfont[4]; //声明静态文本框等控件需用到的字形字号
         time_t startTime, endTime; //声明开始时刻、结束时刻变量
         BOOL isStart=FALSE; //声明是否计时的逻辑变量

b.CMFCtimerDlg::OnInitDialog()程序中,在//TODO:语句后添加代码:

cpp 复制代码
//设置字体
	for (int i = 0; i < 4; i++)
	{
		int choice;
		if (i == 0)choice = 40; //大标题字体使用
		if (i == 1)choice = 25; //年月日等提示字字体使用
		if (i == 2)choice = 20; //文本编辑框显示字体使用
		if (i == 3)choice = 80; //显示跳秒
		cfont[i].CreateFont
		(choice, // nHeight//25
			0, // nWidth
			0, // nEscapement
			0, // nOrientation
			FW_BOLD, // nWeight
			FALSE, // bItalic
			FALSE, // bUnderline
			0, // cStrikeOut
			UNICODE, // nCharSet
			OUT_DEFAULT_PRECIS, // nOutPrecision
			CLIP_DEFAULT_PRECIS, // nClipPrecision
			DEFAULT_QUALITY, // nQuality
			DEFAULT_PITCH | FF_SWISS, // nPitchAndFamily
			_T("黑体")); // lpszFac
	}
//利用函数、控件变量等方法设置控件字体、字形
	GetDlgItem(IDC_TITLE)->SetFont(&cfont[0]);  //"计时器"三字
	m_CTIME.SetFont(&cfont[1]); //"当前时间"四字
	m_YEAR.SetFont(&cfont[1]);  //"年"字
	m_MONTH.SetFont(&cfont[1]); //"月"字
	m_DAY.SetFont(&cfont[1]); //"日"字
	m_HOUR.SetFont(&cfont[1]); //"时"字
	m_MINUTE.SetFont(&cfont[1]); //"分"字
//设置系统计时器(消息函数机制)
	SetTimer(1, 1000, NULL); //设置系统及时器(利用它实现周期性变化显示)
//设置控件焦点到"开始计时"按钮(注意:本函数的返回值要改成FALSE)
	GetDlgItem(IDC_BUTTON1)->SetFocus();

c.由于我们在OnInitDialog()程序中添加了系统计时器语句,接着进行:项目->类向导->消息->选择:WM_TIMER->添加处理程序,在MFCtimerDlg.cpp可以找到下面的函数:

Void CMFCtimerDlg::OnTimer(UINT_PTR nIDEvent),添加下列代码:

cpp 复制代码
	SYSTEMTIME currentTime; //声明时间结构体
	GetLocalTime(&currentTime); // 获得当地时间
	TCHAR temp[12];
	//给年月日时分编辑框设置字形字号并显示当前时间
	wsprintf(temp,L"%d",currentTime.wYear);
	GetDlgItem(IDC_SHOW_YEAR)->SetFont(&cfont[2]);
	GetDlgItem(IDC_SHOW_YEAR)->SetWindowTextW(temp);
	wsprintf(temp, L"%d", currentTime.wMonth);
	GetDlgItem(IDC_SHOW_MONTH)->SetFont(&cfont[2]);
	GetDlgItem(IDC_SHOW_MONTH)->SetWindowTextW(temp);
                wsprintf(temp, L"%d", currentTime.wDay);
	GetDlgItem(IDC_SHOW_DAY)->SetFont(&cfont[2]);
	GetDlgItem(IDC_SHOW_DAY)->SetWindowTextW(temp);
                wsprintf(temp, L"%d", currentTime.wHour);
	GetDlgItem(IDC_SHOW_HOUR)->SetFont(&cfont[2]);
	GetDlgItem(IDC_SHOW_HOUR)->SetWindowTextW(temp);
                wsprintf(temp, L"%d", currentTime.wMinute);
	GetDlgItem(IDC_SHOW_MINUTE)->SetFont(&cfont[2]);
	GetDlgItem(IDC_SHOW_MINUTE)->SetWindowTextW(temp);
	GetDlgItem(IDC_BUTTON1)->SetFont(&cfont[2]);
	GetDlgItem(IDC_BUTTON2)->SetFont(&cfont[2]);
	GetDlgItem(IDC_S)->SetFont(&cfont[1]);
               //以两个编辑框显示读秒
	if (isStart == TRUE) //TRUE读秒 FALSE停止读秒
	{
		time(&endTime);
		TCHAR buf[128];
		wsprintf(buf, L"%d", int(endTime-startTime));
		m_showTime1.SetFont(&cfont[3]);
		m_showTime1.SetWindowTextW(buf);
		GetDlgItem(IDC_SHOWTIME2)->SetFont(&cfont[1]);
		int second = (endTime - startTime) % 60;
		int minute = (endTime - startTime) / 60;
               wsprintf(buf, L"   %d 分 %d 秒", minute,second);
		GetDlgItem(IDC_SHOWTIME2)->SetWindowTextW(buf);
	}
	Circle(); //在"当前时间"后边闪烁一个圆圈,表示屏幕非静止

说明:由于当前时间显示到分,所以不读秒时,程序给人的感觉是静止画面,所以写一个Circle程序,在"当前时间"四字后边以深灰、浅灰不断变化闪烁,给人动感。这里先调用,后边实现程序。在写这个函数之前,先到MFCtimerDlg.h中声明一个变量:

cpp 复制代码
      BOOL myBool = TRUE; //声明绘制圆圈用的逻辑变量

d.我们直接在MFCtimerDlg.cpp内声明并实现 void CMFCtimerDlg::Circle()函数,在这个函数中写上下面代码:

cpp 复制代码
	CDC* pDC=GetDC();//获取当前窗口设备上下文指针
	CRect rect;//这是一个关于视图窗口数据的类,这里定义一个CRect类对象
	GetClientRect(rect);//GetClientRect得到的是相对于窗口客户区左上角的坐标。
	int r = rect.Height() / 20;//设置圆半径
	int x = rect.Height() * 0.4, y = rect.Height() * 0.27;//设置圆心坐标
	CPen grayPen(PS_SOLID, 3, 0x404040);//设置深色圆线型线宽颜色
	CPen whitePen(PS_SOLID, 3, 0xC0C0C0);//设置浅色圆线型线宽颜色
	if (myBool == TRUE) //画深色圆
	{
	 CPen* pOldPen = pDC->SelectObject(&grayPen);
	 pDC->Ellipse(x, y, x + r, y + r);
	 pDC->SelectObject(pOldPen);
	 myBool = !myBool;
   	}
	else //画浅色圆
	{
	CPen* pOldPen = pDC->SelectObject(&whitePen);
	pDC->Ellipse(x, y, x + r, y + r);
	pDC->SelectObject(pOldPen);
	myBool = !myBool;
	}
	ReleaseDC(pDC);

e.在给按钮添加的程序CMFCtimerDlg::OnBnClickedButton1()中写上语句:

cpp 复制代码
	isStart = TRUE; //开始计时
	time(&startTime);

f.在给按钮添加的程序CMFCtimerDlg::OnBnClickedButton2()中写上语句:

cpp 复制代码
	isStart = FALSE; //停止计时

g.到这里,这个小案例基本就完成了。关于程序退出,右键对话框->类向导->点击消息->选择WM_CLOSE->添加处理程序(点击对话框右上角叉的消息)。在MFCtimerDlg.cpp中出现函数:

void CMFCtimerDlg::OnClose() 在TODO:后添加:

cpp 复制代码
	KillTimer(1); //关闭系统计时器
	MessageBox(L"程序即将关闭 。。。");

程序运行效果截图如下:

相关推荐
Moweiii19 分钟前
SDL3 GPU编程探索
c++·游戏引擎·图形渲染·sdl·vulkan
渝妳学C1 小时前
【C++】类和对象(下)
c++
EleganceJiaBao1 小时前
【C语言】结构体模块化编程
c语言·c++·模块化·static·结构体·struct·耦合
xianwu5431 小时前
反向代理模块。开发
linux·开发语言·网络·c++·git
Bucai_不才2 小时前
【C++】初识C++之C语言加入光荣的进化(上)
c语言·c++·面向对象
木向2 小时前
leetcode22:括号问题
开发语言·c++·leetcode
筑基.2 小时前
basic_ios及其衍生库(附 GCC libstdc++源代码)
开发语言·c++
yuyanjingtao2 小时前
CCF-GESP 等级考试 2023年12月认证C++三级真题解析
c++·青少年编程·gesp·csp-j/s·编程等级考试
王老师青少年编程3 小时前
gesp(二级)(12)洛谷:B3955:[GESP202403 二级] 小杨的日字矩阵
c++·算法·矩阵·gesp·csp·信奥赛
2402_857583494 小时前
“协同过滤技术实战”:网上书城系统的设计与实现
java·开发语言·vue.js·科技·mfc