【问题标题】:SetTimer Function on CWinApp failing to be setCWinApp 上的 SetTimer 函数设置失败
【发布时间】:2018-10-03 19:23:09
【问题描述】:

我目前正在制作一个 C++ MFC 应用程序,我需要一个计时器来每隔 30 秒左右调用一个名为 OnTimer 的函数。现在,我有一个看起来像这样的类:

class CMyApp : public CWinApp
{
    // Do some stuff...
    DECLARE_MESSAGE_MAP()

    BOOL InitInstance()
    {
        // m_pMainWnd is an object in CWinApp that allows me to render a window

        m_pMainWnd->ShowWindow(SW_SHOWMAXIMIZED);

        // Do some stuff with this window

        ::SetTimer(NULL, 0, 30000, 0);
    }

    afx_msg void OnTimer(WPARAM wParam, LPARAM lParam)
    {
        // I want this function to execute every 30 seconds
        // This function manipulates the window
    }
}

BEGIN_MESSAGE_MAP(CMyApp, CWinApp)
    ON_THREAD_MESSAGE(WM_TIMER, OnTimer)
END_MESSAGE_MAP()

CMyApp theApp;

此方法确实会调用 OnTimer,但不是每 30 秒调用一次。事实上,OnTimer 现在似乎每分钟被调用数百次。我的问题是:如何设置班级的计时器?

我尝试过的事情

我尝试将用户扩展从 ON_THREAD_MESSAGE 更改为 ON_WM_TIMER、ON_COMMAND 和 ON_MESSAGE。对于不是 ON_THREAD_MESSAGE 的任何内容,我都会收到错误消息

error C2440: 'static_cast' : cannot convert from 'void (__thiscall CMyApp::* )(WPARAM,LPARAM)' to 'LRESULT (__thiscall CWnd::* )(WPARAM,LPARAM)'

我不确定,但我认为 SetTimer 可能正在操作某些 CWinApp 特定功能,而 CWnd SetTimer 没有被操作,并且设置为某个默认值。不过,我在这里几乎一无所知,任何帮助将不胜感激。

【问题讨论】:

  • 调用 CWnd::SetTimer(NULL, 30000, NULL) 得到以下错误:错误 C2352: 'CWnd::SetTimer' : 非法调用非静态成员函数
  • 我尝试从 CMyApp 的 InitInstance 中键入以下行:m_pMainWnd->SetTimer(0, 30000, NULL)。我没有收到任何错误,但 OnTimer 仍然每分钟被调用数百次,即使我将计时器设置为 30 秒。
  • 您可以存储 SetTimer() 返回的结果,并在您的处理程序中将其与 wParam 参数 (if (wParam==nIDEvent)) 进行比较,以确定消息是为您的计时器发送的,还是为另一个计时器发送的。但我更愿意接受@Barmak Shemirani 的建议,即让 MainFrame 处理计时器消息。

标签: c++ mfc


【解决方案1】:

ON_THREAD_MESSAGE 用于用户定义的消息,而不是WM_TIMER

根据SetTimer 文档,窗口句柄必须有效,并且计时器标识符必须非零才能创建新计时器。示例:

::SetTimer(m_pMainWnd->m_hWnd, 1, 30000, NULL);
or 
m_pMainWnd->SetTimer(1, 30000, NULL);

消息可以在主 GUI 窗口中处理。例如CMainFrameCMyCMDIFrameWndm_pMainWnd 指向的任何内容。

BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)
    ON_WM_TIMER()
    ...
END_MESSAGE_MAP()

void CMainFrame::OnTimer(UINT id)
{
    TRACE("OnTimer(%d)\n", id);
}

您也可以在::SetTimer 中使用NULL 作为窗口句柄,但您必须提供回调函数:

VOID CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
{
    TRACE("TimerProc\n");
}

::SetTimer(NULL, 2, 30000, TimerProc);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-08
    • 1970-01-01
    • 2017-09-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多