【问题标题】:Custom message box that automatically disappears自动消失的自定义消息框
【发布时间】:2018-08-23 12:29:39
【问题描述】:

我需要向现有的 MFC 应用程序添加一个自定义消息框,如果用户没有按“确定”,该消息框将在几秒钟后消失。

怎么做?

我对 MFC 基本熟悉,但对 c++ 也很熟悉。

【问题讨论】:

  • 使用无模式对话框。
  • 正如@seccpur 所说,只是添加让无模式对话框自己发布一条 WM_TImer 消息,收到后它可以自行关闭。
  • 您不需要无模式对话框来设置计时器,其处理程序会关闭对话框。此方法适用于 any 对话框。
  • 使用MessageBoxTimeoutW
  • @RbMm:这个问题被标记为winapi。根据定义,未记录的函数不是已记录的 API 表面的一部分。

标签: c++ winapi mfc


【解决方案1】:

无需使用TaskDialogIndirect() 编写自定义对话框即可完成此操作。

基本步骤

  1. TASKDIALOGCONFIG::dwFlags 中设置TDF_CALLBACK_TIMER 位。这将大约每 200 毫秒调用一次回调(如果指定)。
  2. callback function 分配给TASKDIALOGCONFIG::pfCallback
  3. 当使用TDN_TIMER 通知代码调用回调时,将通过wParam 传递给回调的经过时间与您想要的超时值进行比较。要关闭对话框,请发送TDM_CLICK_BUTTON 消息。

您可以花哨地显示进度条 (TDF_SHOW_PROGRESS_BAR),或者只显示您在计时器回调中更新的倒计时文本。见Task Dialog Messages

示例

这是一个使用普通 Windows API 的示例。 MFC 有CTaskDialog 类,但我认为如果它不太依赖MFC,这个答案会更有用。对于非 MFC 用户,只需更改对 tc.hInstancetc.hwndParent 的分配。

TASKDIALOGCONFIG tc{ sizeof(tc) };
tc.hInstance = AfxGetInstanceHandle();
tc.hwndParent = GetSafeHwnd();  // assuming you call this from a dialog member function
tc.dwFlags = TDF_CALLBACK_TIMER | TDF_SIZE_TO_CONTENT;
tc.dwCommonButtons = TDCBF_OK_BUTTON;
tc.pszWindowTitle = L"Task dialog with timeout";
tc.pszContent = L"This dialog will close after 5 seconds!";

DWORD timeout = 5000;  // milliseconds
tc.lpCallbackData = reinterpret_cast<LONG_PTR>( &timeout );

// Assign a lambda function as callback.
tc.pfCallback = []( HWND hwnd, UINT uNotification, WPARAM wParam, LPARAM lParam, LONG_PTR dwRefData )
{
    if( uNotification == TDN_TIMER )
    {
        DWORD* pTimeout = reinterpret_cast<DWORD*>( dwRefData );  // = tc.lpCallbackData
        DWORD timeElapsed = static_cast<DWORD>( wParam );
        if( *pTimeout && timeElapsed >= *pTimeout )
        {
            *pTimeout = 0; // Make sure we don't send the button message multiple times.
            SendMessage( hwnd, TDM_CLICK_BUTTON, IDOK, 0 );
        }
    }
    return S_OK;
};

::TaskDialogIndirect( &tc, nullptr, nullptr, nullptr );

【讨论】:

  • 为什么不直接打电话给MessageBoxTimeoutW
  • @RbMm 未记录和过时的 API。
  • 你在 outdated 下是什么意思?它存在于所有windows版本中,从win2000到最新的win10最低多少
  • @RbMm 由于它没有记录,因此可以在将来的任何时间删除。过时了,因为任务对话框 API 更强大。
  • 我不认为与过时的绑定有多强大。存在不同的 api,其中存在更强大的版本,但这并不意味着这个 api 已经过时了
【解决方案2】:

最简单的方法,如果您只想要超时的消息框,请使用 user32.dll 中的下一个未记录的 api:

extern "C"
WINUSERAPI int WINAPI MessageBoxTimeoutW(IN HWND hWnd, 
                            IN PCWSTR lpText, IN PCWSTR lpCaption, 
                            IN UINT uType, IN WORD wLanguageId, IN DWORD dwMilliseconds);

所有我们需要的 - 将此声明添加到 c++ 代码并与 user32.lib 链接,但我们通常默认这样做。在此之后像往常一样简单地调用它 MessageBoxW 并带有 2 个附加参数。最后一个如何简单地查看 - 以毫秒为单位的 tiemout。

例如:

MessageBoxTimeoutW(HWND_DESKTOP, L"Text", 
    L"Caption", MB_ICONINFORMATION|MB_YESNO, 0, 4000);

注意MessageBoxW 只需调用MessageBoxTimeoutW

int MessageBoxW(
  HWND    hWnd,
  LPCTSTR lpText,
  LPCTSTR lpCaption,
  UINT    uType
)
{
    return MessageBoxTimeoutW(hWnd, lpText, lpCaption, uType, 0, INFINITE);
}

所以前 4 个参数和返回值类似于 MessageBoxW api。如果消息框因超时关闭 - IDTIMEOUT 返回(在 winuser.h 中声明),但 MB_OK 使用(单个 OK 按钮) - 在这种情况下总是 @987654330 @返回。

【讨论】:

    猜你喜欢
    • 2013-12-04
    • 1970-01-01
    • 2011-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多