MFC用高精度计时器实现五段时序控制器

程序功能:使用原有的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

cpp 复制代码
// MultiTimerDlg.h : header file
//

#if !defined(AFX_MULTITIMERDLG_H__INCLUDED_)
#define AFX_MULTITIMERDLG_H__INCLUDED_

#include "CElapsed.h"  // 包含原有的高精度计时器类

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

/////////////////////////////////////////////////////////////////////////////
// CMultiTimerDlg dialog

class CMultiTimerDlg : public CDialog
{
// Construction
public:
    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:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
    //}}AFX_VIRTUAL

// Implementation
protected:
    HICON m_hIcon;

    // 时间段数据
    double m_dTimeStages[5];     // 五个时间段的值
    int m_nCurrentStage;         // 当前执行的时间段(0-4)
    bool m_bRunning;             // 是否正在运行
    bool m_bThreadRunning;       // 线程运行标志
    CElapsed m_elapsedTimer;     // 高精度计时器
    CWinThread* m_pTimerThread;  // 计时器线程指针
    
    // 线程同步
    CRITICAL_SECTION m_csSync;
    
    // 线程函数
    static UINT TimerThreadProc(LPVOID pParam);
    
    // 更新显示
    void UpdateDisplay(int nStage);
    void StopTimer();

    // Generated message map functions
    //{{AFX_MSG(CMultiTimerDlg)
    virtual BOOL OnInitDialog();
    afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
    afx_msg void OnPaint();
    afx_msg HCURSOR OnQueryDragIcon();
    afx_msg void OnButtonStart();
    afx_msg void OnButtonStop();
    afx_msg LRESULT OnUpdateDisplay(WPARAM wParam, LPARAM lParam);
	afx_msg LRESULT OnUpdateTimeOnly(WPARAM wParam, LPARAM lParam);


    //}}AFX_MSG
    DECLARE_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

cpp 复制代码
// MultiTimerDlg.cpp : implementation file
//

#include "stdafx.h"
#include "MultiTimer.h"
#include "MultiTimerDlg.h"
#include <math.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
    CAboutDlg();

// Dialog Data
    //{{AFX_DATA(CAboutDlg)
    enum { IDD = IDD_ABOUTBOX };
    //}}AFX_DATA

    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(CAboutDlg)
    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
    //}}AFX_VIRTUAL

// Implementation
protected:
    //{{AFX_MSG(CAboutDlg)
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
    //{{AFX_DATA_INIT(CAboutDlg)
    //}}AFX_DATA_INIT
}

void CAboutDlg::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_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMultiTimerDlg dialog

CMultiTimerDlg::CMultiTimerDlg(CWnd* pParent /*=NULL*/)
    : CDialog(CMultiTimerDlg::IDD, pParent)
{
    //{{AFX_DATA_INIT(CMultiTimerDlg)
    //}}AFX_DATA_INIT
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
    
    // 初始化成员变量
    m_nCurrentStage = 0;
    m_bRunning = false;
    m_bThreadRunning = false;
    m_pTimerThread = NULL;
    
    // 初始化时间段数据
    for (int i = 0; i < 5; i++)
    {
        m_dTimeStages[i] = 0.0;
    }
    
    InitializeCriticalSection(&m_csSync);
}

void CMultiTimerDlg::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_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMultiTimerDlg message handlers

BOOL CMultiTimerDlg::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 icon
    SetIcon(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"));

	
    return TRUE;
}

void CMultiTimerDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
    if ((nID & 0xFFF0) == IDM_ABOUTBOX)
    {
        CAboutDlg dlgAbout;
        dlgAbout.DoModal();
    }
    else
    {
        CDialog::OnSysCommand(nID, lParam);
    }
}

void CMultiTimerDlg::OnPaint() 
{
    if (IsIconic())
    {
        CPaintDC dc(this); // device context for painting

        SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

        // Center icon in client rectangle
        int cxIcon = GetSystemMetrics(SM_CXICON);
        int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(&rect);
        int x = (rect.Width() - cxIcon + 1) / 2;
        int y = (rect.Height() - cyIcon + 1) / 2;

        // Draw the icon
        dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
        CDialog::OnPaint();
    }
}

HCURSOR CMultiTimerDlg::OnQueryDragIcon()
{
    return (HCURSOR) m_hIcon;
}

void CMultiTimerDlg::OnButtonStart() 
{
    // 如果正在运行,不允许再次启动
    if (m_bRunning)
    {
        MessageBox(_T("程序正在运行,请等待完成或点击停止"), _T("提示"), MB_ICONINFORMATION);
        return;
    }
    
    // 读取五个时间段的值
    CString strTime;
    for (int i = 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);
}

void CMultiTimerDlg::OnButtonStop() 
{
    if (!m_bRunning) return;
    
    // 停止计时器
    StopTimer();
     
    UpdateDisplay(m_nCurrentStage);
    
    // 启用启动按钮,禁用停止按钮
    GetDlgItem(IDC_BUTTON_START)->EnableWindow(TRUE);
    GetDlgItem(IDC_BUTTON_STOP)->EnableWindow(FALSE);
}

void CMultiTimerDlg::StopTimer()
{
    if (!m_bRunning) return;
    
    m_bThreadRunning = false;
    m_bRunning = false;
    
    if (m_pTimerThread)
    {
        WaitForSingleObject(m_pTimerThread->m_hThread, 1000);
        m_pTimerThread = NULL;
    }
}

LRESULT CMultiTimerDlg::OnUpdateTimeOnly(WPARAM wParam, LPARAM lParam)
{
    double dCurrentTime = *(double*)lParam;
    
    // 只更新第二个静态文本(时间值)
    CString strTime;
    strTime.Format(_T("%.2f"), dCurrentTime);
    SetDlgItemText(IDC_STATIC_CURRENT_TIME, strTime);
    
    // 释放内存
    delete (double*)lParam;
    
    return 0;
}

LRESULT CMultiTimerDlg::OnUpdateDisplay(WPARAM wParam, LPARAM lParam)
{
    int nStage = (int)wParam;
    double dCurrentTime = *(double*)lParam;
    
    UpdateDisplay(nStage);
    
    // 释放动态分配的内存
    delete (double*)lParam;
    
    return 0;
}

void CMultiTimerDlg::UpdateDisplay(int nStage)
{
    // 更新阶段显示
    CString strStage;
    strStage.Format(_T("时间%d"), nStage + 1);
    SetDlgItemText(IDC_STATIC_STAGE, strStage);
    
    // 更新时间显示
    
}

UINT CMultiTimerDlg::TimerThreadProc(LPVOID pParam)
{
    CMultiTimerDlg* pDlg = (CMultiTimerDlg*)pParam;
    const double UPDATE_INTERVAL = 0.01; // 0.01秒更新间隔
    
    CElapsed updateTimer;
    updateTimer.Start();
    
    double dTotalElapsedTime = 0.0;
    int nCurrentStage = 0;
    double dStageStartTime = 0.0;
    int nLastDisplayedStage = -1;
    
    while (pDlg->m_bThreadRunning && nCurrentStage < 5)
    {
        // 计算总经过时间
        dTotalElapsedTime = pDlg->m_elapsedTimer.NowSec();
        
        // 计算当前阶段内的经过时间
        double dElapsedInStage = 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 = new double(0.0);
            pDlg->PostMessage(WM_UPDATE_DISPLAY, (WPARAM)nCurrentStage, (LPARAM)pNewStageTime);
            nLastDisplayedStage = nCurrentStage;
        }
        else
        {
            // 发送当前时间更新
            double* pCurrentTime = new double(dElapsedInStage);
             pDlg->PostMessage(WM_UPDATE_TIME_ONLY, 0, (LPARAM)pCurrentTime);
        }
        
        // 精确等待
        double dWaitTime = 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)new double(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);
    }
    
    return 0;
}

运行程序

相关推荐
眠りたいです6 小时前
基于脚手架微服务的视频点播系统-服务端开发部分(补充)文件子服务问题修正
c++·微服务·云原生·架构
ULTRA??7 小时前
各种排序算法时间复杂度分析和实现和优势
c++·python·算法·排序算法
博语小屋7 小时前
简单线程池实现(单例模式)
linux·开发语言·c++·单例模式
墨雪不会编程7 小时前
C++基础语法篇八 ——【类型转换、再探构造、友元】
java·开发语言·c++
yuuki2332337 小时前
【C++】内存管理
java·c++·算法
刃神太酷啦7 小时前
Linux 进程核心原理精讲:从体系结构到实战操作(含 fork / 状态 / 优先级)----《Hello Linux!》(6)
java·linux·运维·c语言·c++·算法·leetcode
一个不知名程序员www7 小时前
算法学习入门---二叉树
c++·算法
小李小李快乐不已7 小时前
数组&&矩阵理论基础
数据结构·c++·线性代数·算法·leetcode·矩阵
coderxiaohan7 小时前
【C++】用哈希表封装unordered_map和unordered_set
开发语言·c++·散列表