【问题标题】:OnTimer method not working in MFCOnTimer 方法在 MFC 中不起作用
【发布时间】:2013-10-13 14:52:33
【问题描述】:

我在 VS2010 中创建了一个基于 MFC 对话框的应用程序,并希望添加计时器以每 3 秒更新一次图片控制器。但 OnTimer 方法从未奏效。

我使用类向导将WM_TIMER添加到消息队列中,结果如下:

BEGIN_MESSAGE_MAP(CxxxxDlg, CDialogEx)
    ON_WM_PAINT()
    ON_BN_CLICKED(IDOK, &CxxxxDlg::OnBnClickedOK)
    ON_WM_TIMER()
END_MESSAGE_MAP()

在 xxxxDlg.cpp 中,我将 SetTimer 方法放在 OnInitDialog 中:

BOOL CxxxxDlg::OnInitDialog()
{
    CDialog::OnInitDialog();
    SetIcon(m_hIcon, TRUE);
    SetIcon(m_hIcon, TRUE);

    _imageCounter = 1;
    _isMale = 3;
    _testNum = 0;

    SetTimer(123, 2000, NULL);

    bFullScreen = false;
    OnFullShow();
    updateImages();
    UpdateData();

    return TRUE;
}

在 xxxdlv.h 中声明了 OnTimer 方法:

public:
    afx_msg void OnTimer(UINT_PTR nIDEvent);

当我运行应用程序时,SetTimer 返回 123。所以这里应该一切正常。 但程序始终没有到达我在 OnTimer 方法的第一行设置的断点!

然后我写了另一个 hello world 项目只是为了测试计时器。我以完全相同的方式设置了计时器,并且效果很好。

所以我认为 OnFullShow() 方法可能是问题所在。此方法用于将窗口更改为全屏模式。我评论了这一行,但 OnTimer 仍然没有工作。

我已经检查了问题here。但这无济于事。

有谁知道问题出在哪里?谢谢!

PS。我确实收到了一些内存泄漏的警告。这有关系吗?

【问题讨论】:

  • 您的WM_PAINT 函数是否会以某种方式循环,以致无法处理WM_TIMER 消息? [尝试注释掉您的绘图功能以进行检查]
  • WM_TIMER 是低优先级消息(如WM_PAINTWM_MOUSEMOVE)。仅当消息队列为空且没有无效窗口区域且没有鼠标输入时才会生成它。如果您未能满足其中任何一个条件,您将永远不会收到WM_TIMER,即使计时器已正确安装。
  • @EdwardClements 我将这一行注释掉,但问题仍然存在。谢谢。
  • @IInspectable 谢谢。你让我想起了我用于键盘的PreTranslateMessage 方法。如果消息的级别很重要,这个方法可能不会收到WM_TIMER,不是吗?我稍后会更新我的问题。再次感谢:)
  • 有趣的是,您提到了 PreTranslateMessage。默认情况下,您从该方法返回什么?对于您未翻译的所有其他消息,您应该返回 FALSE。

标签: c++ visual-studio-2010 timer mfc message-queue


【解决方案1】:

感谢@IInspectable。我找到了技术支持here。它充分解释了原因并提供了一种解决方案:

// Rewrite PreTranslateMessage method
BOOL CMyApp::PreTranslateMessage( MSG *pMsg )
{
   // If this is a timer callback message let it pass on through to the
   // DispatchMessage call.
   if( (pMsg->message==WM_TIMER) && (pMsg->hwnd==NULL) )
       return FALSE;
   ...
   // The rest of your PreTranslateMessage goes here.
   ...

   return CWinApp::PreTranslateMessage(pMsg);
}

这个解决方案没有解决我的问题,但给了我一个提示。应该重写PreTranslateMessage 方法以让WM_TIMER 传递到 DispatchMessage 调用。 但如果你使用PreTranslateMessage处理其他消息,例如WM_KEYDOWN,上面的解决方案可能不起作用。好像是优先级的问题。最后,我使用switch而不是if来解决它:

// Rewrite PreTranslateMessage method
BOOL CMyApp::PreTranslateMessage( MSG *pMsg )
{
   // If this is a timer callback message let it pass on through to the
   // DispatchMessage call.
   switch(pMsg->message)
   {
    case WM_KEYDOWN: // your codes
    case WM_TIMER: return false;
    ...
   }
   ...
   // The rest of your PreTranslateMessage goes here.
   ...

   return CWinApp::PreTranslateMessage(pMsg);
}

希望对遇到类似问题的人有所帮助。

PS。 pMsg->hwnd==NULL 已在 switch 中删除,我不确定它是否安全。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-04-16
    • 1970-01-01
    • 2023-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多