• VC计时器的一个使用心得


                                                                                   朱金灿
     
    最近使用VC的计时器。计时器一般是先设置一个Timer,然后响应WM_TIMER消息,然后销毁计时器。但是我发现在哪里设置计时器和销毁计时器是有讲究的。
     
    开始我的代码是这样的:
    CMainFrame::CMainFrame()
    {
           // TODO: add member initialization code here
           SetTimer(1, 5000, 0);
    }
    // WM_TIMER消息响应函数
    void CMainFrame::OnTimer(UINT nIDEvent)
    {
           // TODO: Add your message handler code here and/or call default
           AfxMessageBox("Hello World!");
           CFrameWnd::OnTimer(nIDEvent);
    }
     
    CMainFrame::~CMainFrame()
    {
           KillTimer(1);
    }
     
    编译结果是,debug模式编译下出现Assertion Fauled,

    调试时发现出错是在BOOL CTestTimerApp::InitInstance()函数中的一句:
           if (!ProcessShellCommand(cmdInfo))
                  return FALSE;
    发生的。
     
    但是在release模式编译成功。想来是因为release模式忽略Assert宏的缘故,但是运行程序却没有Hello World!的对话框弹出。
     
         后来我想莫非是SetTimer(1, 5000, 0);函数放置的地方不对的缘故。后来我把它
    框架类的OnCreate函数。
    int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
           if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
                  return -1;
          
           if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
                  | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
                  !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
           {
                  TRACE0("Failed to create toolbar/n");
                  return -1;      // fail to create
           }
     
           if (!m_wndStatusBar.Create(this) ||
                  !m_wndStatusBar.SetIndicators(indicators,
                   sizeof(indicators)/sizeof(UINT)))
           {
                  TRACE0("Failed to create status bar/n");
                  return -1;      // fail to create
           }
     
           // TODO: Delete these three lines if you don't want the toolbar to
           // be dockable
           m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
           EnableDocking(CBRS_ALIGN_ANY);
           DockControlBar(&m_wndToolBar);
        SetTimer(1, 5000, 0); // 在这里设置计时器
           return 0;
    }
     
    这样编译debugm通过, Hello World!的对话框也出来了。但是在程序退出时检测到有内存泄露:Detected memory leaks!
     
    我估计在销毁计时器的代码有问题。于是我把放到响应WM_DESTROY消息的函数里。
    void CMainFrame::OnDestroy()
    {
           CFrameWnd::OnDestroy();
          
           // TODO: Add your message handler code here
           KillTimer(1);
    }
          为什么设置计时起不能放在窗口类构造函数,销毁计时器不能放在窗口类的析构函数里?让我们看看MFC的源码:
    CWnd::SetTimer(UINT nIDEvent, UINT nElapse,
                  void (CALLBACK* lpfnTimer)(HWND, UINT, UINT, DWORD))
           { ASSERT(::IsWindow(m_hWnd)); return ::SetTimer(m_hWnd, nIDEvent, nElapse,
                  (TIMERPROC)lpfnTimer); }
     
    果然有一个ASSERT宏。而且这个宏很明确地告诉我们必须在窗口句柄有效的时候才能设置计时器。同样道理,在销毁计时器时也必须确保窗口句柄是有效的。
     
  • 相关阅读:
    高性能MySQL学习总结二----常见数据类型选择及优化
    springboot admin图文+视频教程
    xxl-job图文教程+视频讲解
    mybatis-plus视频教程
    springcloud视频教程
    springcloud系统化学习图文+视频教程
    docker系统化学习图文+视频教程
    【分享】docker全套视频教程
    是用Git还是SVN?
    NOIP知识点汇总
  • 原文地址:https://www.cnblogs.com/lanzhi/p/6471261.html
Copyright © 2020-2023  润新知