程序功能:使用原有的CElapsed类实现高精度计时在五个编辑框输入五个不同时间段的时间值(精确到0.01秒),点击启动后,依次从第一个到第五个编辑框的时间开始计时,每个时间段当前的实时值显示在第二个静态文本中,同时第一个静态文本显示对应的时间段“时间1”到“时间5”。停止按钮可以随时结束整个过程。程序启动后再点启动无效,一直到程序执行结束,或点击停止按钮后启动才有效,点击停止按钮时这个时间段当前的实时值显示在第二个静态文本中。
设计思路:
1.启动按钮点击后,读取五个编辑框的时间,然后启动一个工作线程。
2.工作线程依次处理五个时间段,每个时间段开始时,更新当前阶段显示,然后开始计时,并实时更新当前时间段的经过时间,要实时显示,所以需要频繁更新UI。我们使用PostMessage将更新信息发送到主线程。工作线程函数中,我们将依次执行五个阶段。每个阶段中,我们循环检查是否达到设定时间,同时检查停止信号。
3.每个时间段计时完成后,自动进入下一个时间段,每个时间段开始时重置CElapsed对象,直到五个时间段全部完成。
4.停止按钮可以中断计时过程。
对话框资源设计:
5个编辑框:IDC_EDIT_TIME1 到 IDC_EDIT_TIME5
2个静态文本:
IDC_STATIC_STAGE:显示当前时间段(“时间1"到"时间5”)
IDC_STATIC_CURRENT_TIME:显示当前时间段的实时值
启动按钮:IDC_BUTTON_START
停止按钮:IDC_BUTTON_STOP
头文件 MultiTimerDlg.h
// MultiTimerDlg.h : header file//#if!defined(AFX_MULTITIMERDLG_H__INCLUDED_)#defineAFX_MULTITIMERDLG_H__INCLUDED_#include"CElapsed.h"// 包含原有的高精度计时器类#if_MSC_VER>1000#pragmaonce#endif// _MSC_VER > 1000/////////////////////////////////////////////////////////////////////////////// CMultiTimerDlg dialogclassCMultiTimerDlg:publicCDialog{// Constructionpublic:CMultiTimerDlg(CWnd*pParent=NULL);// standard constructor// Dialog Data//{{AFX_DATA(CMultiTimerDlg)enum{IDD=IDD_MULTITIMER_DIALOG};// NOTE: the ClassWizard will add data members here//}}AFX_DATA// ClassWizard generated virtual function overrides//{{AFX_VIRTUAL(CMultiTimerDlg)protected:virtualvoidDoDataExchange(CDataExchange*pDX);// DDX/DDV support//}}AFX_VIRTUAL// Implementationprotected:HICON m_hIcon;// 时间段数据doublem_dTimeStages[5];// 五个时间段的值intm_nCurrentStage;// 当前执行的时间段(0-4)boolm_bRunning;// 是否正在运行boolm_bThreadRunning;// 线程运行标志CElapsed m_elapsedTimer;// 高精度计时器CWinThread*m_pTimerThread;// 计时器线程指针// 线程同步CRITICAL_SECTION m_csSync;// 线程函数staticUINTTimerThreadProc(LPVOID pParam);// 更新显示voidUpdateDisplay(intnStage);voidStopTimer();// Generated message map functions//{{AFX_MSG(CMultiTimerDlg)virtualBOOLOnInitDialog();afx_msgvoidOnSysCommand(UINT nID,LPARAM lParam);afx_msgvoidOnPaint();afx_msg HCURSOROnQueryDragIcon();afx_msgvoidOnButtonStart();afx_msgvoidOnButtonStop();afx_msg LRESULTOnUpdateDisplay(WPARAM wParam,LPARAM lParam);afx_msg LRESULTOnUpdateTimeOnly(WPARAM wParam,LPARAM lParam);//}}AFX_MSGDECLARE_MESSAGE_MAP()private:enum{WM_UPDATE_DISPLAY=WM_USER+100,WM_UPDATE_TIME_ONLY=WM_USER+101// 新增:只更新时间值的消息};};//{{AFX_INSERT_LOCATION}}// Microsoft Visual C++ will insert additional declarations immediately before the previous line.#endif// !defined(AFX_MULTITIMERDLG_H__INCLUDED_)实现文件 MultiTimerDlg.cpp
// MultiTimerDlg.cpp : implementation file//#include"stdafx.h"#include"MultiTimer.h"#include"MultiTimerDlg.h"#include<math.h>#ifdef_DEBUG#definenewDEBUG_NEW#undefTHIS_FILEstaticcharTHIS_FILE[]=__FILE__;#endif/////////////////////////////////////////////////////////////////////////////// CAboutDlg dialog used for App AboutclassCAboutDlg:publicCDialog{public:CAboutDlg();// Dialog Data//{{AFX_DATA(CAboutDlg)enum{IDD=IDD_ABOUTBOX};//}}AFX_DATA// ClassWizard generated virtual function overrides//{{AFX_VIRTUAL(CAboutDlg)protected:virtualvoidDoDataExchange(CDataExchange*pDX);// DDX/DDV support//}}AFX_VIRTUAL// Implementationprotected://{{AFX_MSG(CAboutDlg)//}}AFX_MSGDECLARE_MESSAGE_MAP()};CAboutDlg::CAboutDlg():CDialog(CAboutDlg::IDD){//{{AFX_DATA_INIT(CAboutDlg)//}}AFX_DATA_INIT}voidCAboutDlg::DoDataExchange(CDataExchange*pDX){CDialog::DoDataExchange(pDX);//{{AFX_DATA_MAP(CAboutDlg)//}}AFX_DATA_MAP}BEGIN_MESSAGE_MAP(CAboutDlg,CDialog)//{{AFX_MSG_MAP(CAboutDlg)// No message handlers//}}AFX_MSG_MAPEND_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////// CMultiTimerDlg dialogCMultiTimerDlg::CMultiTimerDlg(CWnd*pParent/*=NULL*/):CDialog(CMultiTimerDlg::IDD,pParent){//{{AFX_DATA_INIT(CMultiTimerDlg)//}}AFX_DATA_INITm_hIcon=AfxGetApp()->LoadIcon(IDR_MAINFRAME);// 初始化成员变量m_nCurrentStage=0;m_bRunning=false;m_bThreadRunning=false;m_pTimerThread=NULL;// 初始化时间段数据for(inti=0;i<5;i++){m_dTimeStages[i]=0.0;}InitializeCriticalSection(&m_csSync);}voidCMultiTimerDlg::DoDataExchange(CDataExchange*pDX){CDialog::DoDataExchange(pDX);//{{AFX_DATA_MAP(CMultiTimerDlg)//}}AFX_DATA_MAP}BEGIN_MESSAGE_MAP(CMultiTimerDlg,CDialog)//{{AFX_MSG_MAP(CMultiTimerDlg)ON_WM_SYSCOMMAND()ON_WM_PAINT()ON_WM_QUERYDRAGICON()ON_BN_CLICKED(IDC_BUTTON_START,OnButtonStart)ON_BN_CLICKED(IDC_BUTTON_STOP,OnButtonStop)ON_MESSAGE(WM_UPDATE_DISPLAY,OnUpdateDisplay)ON_MESSAGE(WM_UPDATE_TIME_ONLY,OnUpdateTimeOnly)// 新增消息处理//}}AFX_MSG_MAPEND_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////// CMultiTimerDlg message handlersBOOLCMultiTimerDlg::OnInitDialog(){CDialog::OnInitDialog();// Add "About..." menu item to system menu.ASSERT((IDM_ABOUTBOX&0xFFF0)==IDM_ABOUTBOX);ASSERT(IDM_ABOUTBOX<0xF000);CMenu*pSysMenu=GetSystemMenu(FALSE);if(pSysMenu!=NULL){CString strAboutMenu;strAboutMenu.LoadString(IDS_ABOUTBOX);if(!strAboutMenu.IsEmpty()){pSysMenu->AppendMenu(MF_SEPARATOR);pSysMenu->AppendMenu(MF_STRING,IDM_ABOUTBOX,strAboutMenu);}}SetIcon(m_hIcon,TRUE);// Set big iconSetIcon(m_hIcon,FALSE);// Set small icon// 初始化编辑框默认值SetDlgItemText(IDC_EDIT_TIME1,_T("5.0"));SetDlgItemText(IDC_EDIT_TIME2,_T("10.0"));SetDlgItemText(IDC_EDIT_TIME3,_T("8.0"));SetDlgItemText(IDC_EDIT_TIME4,_T("12.0"));SetDlgItemText(IDC_EDIT_TIME5,_T("6.0"));// 初始化显示SetDlgItemText(IDC_STATIC_STAGE,_T("时间1"));SetDlgItemText(IDC_STATIC_CURRENT_TIME,_T("0.00"));returnTRUE;}voidCMultiTimerDlg::OnSysCommand(UINT nID,LPARAM lParam){if((nID&0xFFF0)==IDM_ABOUTBOX){CAboutDlg dlgAbout;dlgAbout.DoModal();}else{CDialog::OnSysCommand(nID,lParam);}}voidCMultiTimerDlg::OnPaint(){if(IsIconic()){CPaintDCdc(this);// device context for paintingSendMessage(WM_ICONERASEBKGND,(WPARAM)dc.GetSafeHdc(),0);// Center icon in client rectangleintcxIcon=GetSystemMetrics(SM_CXICON);intcyIcon=GetSystemMetrics(SM_CYICON);CRect rect;GetClientRect(&rect);intx=(rect.Width()-cxIcon+1)/2;inty=(rect.Height()-cyIcon+1)/2;// Draw the icondc.DrawIcon(x,y,m_hIcon);}else{CDialog::OnPaint();}}HCURSORCMultiTimerDlg::OnQueryDragIcon(){return(HCURSOR)m_hIcon;}voidCMultiTimerDlg::OnButtonStart(){// 如果正在运行,不允许再次启动if(m_bRunning){MessageBox(_T("程序正在运行,请等待完成或点击停止"),_T("提示"),MB_ICONINFORMATION);return;}// 读取五个时间段的值CString strTime;for(inti=0;i<5;i++){UINT nEditID=IDC_EDIT_TIME1+i;GetDlgItemText(nEditID,strTime);m_dTimeStages[i]=atof(strTime);if(m_dTimeStages[i]<=0.0){CString strMsg;strMsg.Format(_T("请输入有效的时间%d(大于0)"),i+1);MessageBox(strMsg,_T("错误"),MB_ICONERROR);return;}}// 重置状态m_nCurrentStage=0;m_bRunning=true;m_bThreadRunning=true;// 启动计时器m_elapsedTimer.Start();// 更新初始显示UpdateDisplay(0);// 启动计时器线程m_pTimerThread=AfxBeginThread(TimerThreadProc,this,THREAD_PRIORITY_NORMAL);// 禁用启动按钮,启用停止按钮GetDlgItem(IDC_BUTTON_START)->EnableWindow(FALSE);GetDlgItem(IDC_BUTTON_STOP)->EnableWindow(TRUE);}voidCMultiTimerDlg::OnButtonStop(){if(!m_bRunning)return;// 停止计时器StopTimer();UpdateDisplay(m_nCurrentStage);// 启用启动按钮,禁用停止按钮GetDlgItem(IDC_BUTTON_START)->EnableWindow(TRUE);GetDlgItem(IDC_BUTTON_STOP)->EnableWindow(FALSE);}voidCMultiTimerDlg::StopTimer(){if(!m_bRunning)return;m_bThreadRunning=false;m_bRunning=false;if(m_pTimerThread){WaitForSingleObject(m_pTimerThread->m_hThread,1000);m_pTimerThread=NULL;}}LRESULTCMultiTimerDlg::OnUpdateTimeOnly(WPARAM wParam,LPARAM lParam){doubledCurrentTime=*(double*)lParam;// 只更新第二个静态文本(时间值)CString strTime;strTime.Format(_T("%.2f"),dCurrentTime);SetDlgItemText(IDC_STATIC_CURRENT_TIME,strTime);// 释放内存delete(double*)lParam;return0;}LRESULTCMultiTimerDlg::OnUpdateDisplay(WPARAM wParam,LPARAM lParam){intnStage=(int)wParam;doubledCurrentTime=*(double*)lParam;UpdateDisplay(nStage);// 释放动态分配的内存delete(double*)lParam;return0;}voidCMultiTimerDlg::UpdateDisplay(intnStage){// 更新阶段显示CString strStage;strStage.Format(_T("时间%d"),nStage+1);SetDlgItemText(IDC_STATIC_STAGE,strStage);// 更新时间显示}UINTCMultiTimerDlg::TimerThreadProc(LPVOID pParam){CMultiTimerDlg*pDlg=(CMultiTimerDlg*)pParam;constdoubleUPDATE_INTERVAL=0.01;// 0.01秒更新间隔CElapsed updateTimer;updateTimer.Start();doubledTotalElapsedTime=0.0;intnCurrentStage=0;doubledStageStartTime=0.0;intnLastDisplayedStage=-1;while(pDlg->m_bThreadRunning&&nCurrentStage<5){// 计算总经过时间dTotalElapsedTime=pDlg->m_elapsedTimer.NowSec();// 计算当前阶段内的经过时间doubledElapsedInStage=dTotalElapsedTime-dStageStartTime;// 如果当前阶段时间已到,切换到下一个阶段if(dElapsedInStage>=pDlg->m_dTimeStages[nCurrentStage]){// 进入下一个阶段nCurrentStage++;if(nCurrentStage>=5){// 所有阶段完成break;}// 更新阶段开始时间dStageStartTime=dTotalElapsedTime;dElapsedInStage=0.0;// 发送阶段切换消息EnterCriticalSection(&pDlg->m_csSync);pDlg->m_nCurrentStage=nCurrentStage;LeaveCriticalSection(&pDlg->m_csSync);double*pNewStageTime=newdouble(0.0);pDlg->PostMessage(WM_UPDATE_DISPLAY,(WPARAM)nCurrentStage,(LPARAM)pNewStageTime);nLastDisplayedStage=nCurrentStage;}else{// 发送当前时间更新double*pCurrentTime=newdouble(dElapsedInStage);pDlg->PostMessage(WM_UPDATE_TIME_ONLY,0,(LPARAM)pCurrentTime);}// 精确等待doubledWaitTime=UPDATE_INTERVAL-fmod(updateTimer.NowSec(),UPDATE_INTERVAL);if(dWaitTime>0){Sleep(static_cast<DWORD>(dWaitTime*1000));}}// 线程结束处理if(nCurrentStage>=5){// 所有阶段完成EnterCriticalSection(&pDlg->m_csSync);pDlg->m_bRunning=false;pDlg->m_bThreadRunning=false;LeaveCriticalSection(&pDlg->m_csSync);// 发送完成消息pDlg->PostMessage(WM_UPDATE_DISPLAY,(WPARAM)4,(LPARAM)newdouble(pDlg->m_dTimeStages[4]));// 启用启动按钮,禁用停止按钮pDlg->GetDlgItem(IDC_BUTTON_START)->EnableWindow(TRUE);pDlg->GetDlgItem(IDC_BUTTON_STOP)->EnableWindow(FALSE);// MessageBox(pDlg->GetSafeHwnd(), _T("所有时间段执行完成!"), _T("完成"), MB_ICONINFORMATION);}return0;}运行程序