65.9K
CodeProject 正在变化。 阅读更多。
Home

Vista 中的 C++ 实用功能:使用任务对话框显示友好消息

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.87/5 (19投票s)

2006年12月12日

7分钟阅读

viewsIcon

102082

downloadIcon

763

使用 Vista TaskDialog API 替换 MessageBox。

目录

引言

在本文的Vista炫酷功能系列中,我将介绍新的TaskDialog() API,它被设计为比MessageBox()更用户友好的替代品。TaskDialog()不仅显示了更美观的用户界面,而且对开发者来说也更简单,因为它处理了自动加载字符串资源等细节。

本文是针对Vista的RTM版本编写的,使用了Visual Studio 2005、WTL 7.5以及Windows SDK。有关在哪里下载这些组件的更多信息,请参阅第一个Vista炫酷功能文章的介绍

虽然使用MessageBox()显示简单消息一直都很容易,但有时它会很麻烦,尤其是当你的应用程序考虑国际化,并且UI字符串位于资源DLL中时:MessageBox()不像DialogBox()那样可以传递资源ID,它没有提供加载字符串资源的功能。还有一个缺点是,消息框只能显示预定义的按钮集;如果你想要一个“重试”按钮而不是“忽略”按钮,那就没办法了。

虽然MessageBoxIndirect()解决了这些缺点,但该API仍然对可以显示的按钮有限制。TaskDialog()解决了这个问题,并提供了一个更易于使用且更灵活的API。

TaskDialog API

TaskDialog()的原型是

HRESULT TaskDialog ( HWND hWndParent, HINSTANCE hInstance,
                     PCWSTR pszWindowTitle, PCWSTR pszMainInstruction,
                     PCWSTR pszContent,
                     TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtons,
                     PCWSTR pszIcon, int *pnButton );

参数如下:

hWndParent
将是任务对话框父级的窗口。与MessageBox()一样,在显示任务对话框时,此窗口将被禁用。如果不想让任务对话框有父级,则传递NULL(请参阅Raymond Chen的这篇博客文章,了解为什么传递GetDesktopWindow()是错误的)。
hInstance
如果以下任何参数是字符串或图标资源的ID,请将此参数设置为包含资源的模块的HINSTANCE
pszWindowTitle
要在任务对话框标题栏中显示的字符串。这可以是零终止的Unicode字符串或字符串资源ID。在传递资源ID时,请在ID上使用MAKEINTRESOURCE宏。(如果您是为ANSI字符集构建的,请显式使用Unicode宏MAKEINTRESOURCEW而不是MAKEINTRESOURCE。)
pszMainInstruction
要在任务对话框顶部、图标旁边显示的字符串。此文本以较大的字体和不同的颜色显示,使其看起来像文档中的标题。与pszWindowTitle一样,此参数可以是C风格字符串或字符串资源ID。
pszContent
要在任务对话框正文中显示的字符串。此参数也可以是C风格字符串或字符串资源ID。
dwCommonButtons
一组标志,指示要在对话框中显示的按钮。要拥有多个按钮,请使用逻辑或运算符组合所需按钮的标志。可能的标志是:TDCBF_OK_BUTTONTDCBF_YES_BUTTONTDCBF_NO_BUTTONTDCBF_CANCEL_BUTTONTDCBF_RETRY_BUTTONTDCBF_CLOSE_BUTTON

按钮的组合没有限制;您可以在此参数中设置任意数量的标志。如果传递0,则默认行为是只显示一个“确定”按钮。请注意,除非传递了TDCBF_CANCEL_BUTTON,否则无法使用Esc键或Alt+F4键关闭对话框。

pszIcon
要在任务对话框中显示的图标的资源ID。与字符串参数一样,您必须在ID上使用MAKEINTRESOURCEMAKEINTRESOURCEW宏。您也可以传递以下预定义值之一来使用系统图标:TD_ERROR_ICONTD_WARNING_ICONTD_INFORMATION_ICONTD_SHIELD_ICONTD_SHIELD_ICON显示UAC盾牌(),并且只应用于指示用户需要提升权限才能执行管理任务的情况。您也可以传递NULL,如果您不想要任何图标。
pnButton
指向int的指针,该指针设置为以下值之一,以指示用户单击了哪个按钮:IDOKIDYESIDNOIDCANCELIDRETRYIDCLOSE。如果在dwCommonButtons中传递了TDCBF_CANCEL_BUTTON,则用户按下Esc或Alt+F4时,*pnButton将设置为IDCANCEL。如果TaskDialog()失败,则该值将设置为0。如果不需要知道单击了哪个按钮,则可以将此参数传递为NULL

TaskDialog()的返回值是一个HRESULT,指示函数是否成功。如果无法加载资源或在内存不足的情况下,它可能会失败。

如果pszWindowTitleNULL,则使用可执行文件的文件名作为标题文本。如果不需要在对话框中显示某段文本,则pszMainInstructionpszContent可以为NULL。此外,pszMainInstructionpszContent可以是多行字符串;在字符串中插入换行符('\n')表示换行。

请注意,字符串参数始终是Unicode字符串。与XP和Vista中添加的许多API一样,没有接受ANSI字符串的版本。

使用TaskDialog的示例

使用C风格字符串的TaskDialog

让我们从一个只使用硬编码字符串的示例开始。我们显示此消息的上下文是,我们的应用程序已检测到有可用更新,并且我们正在询问用户是否要立即获取更新。

void CTheApp::OnUpdateAvailable()
{
HRESULT hr;
int nClickedButton;
LPCWSTR szTitle = L"Mike's AntiFluff Scanner",
  szHeader = L"An update for Mike's AntiFluff Scanner is available",
  szBodyText = L"Version 2007.1 of Mike's AntiFluff Scanner has been released." \
               L"Do you want to download the update now?";
 
  hr = TaskDialog ( m_hWnd, NULL,
                    szTitle, szHeader, szBodyText,
                    TDCBF_YES_BUTTON|TDCBF_NO_BUTTON,
                    NULL, &nClickedButton );
 
  if ( SUCCEEDED(hr) && IDYES == nClickedButton )
    {
    // download the update...
    }
}

这是任务对话框,显示了我们传入的字符串和按钮

我们还可以使用pszIcon参数添加一个信息图标

  hr = TaskDialog ( m_hWnd, NULL,
                    szTitle, szHeader, szBodyText,
                    TDCBF_YES_BUTTON|TDCBF_NO_BUTTON,
                    TD_INFORMATION_ICON, &nClickedButton );

使用资源的TaskDialog

现在让我们看看当字符串和图标位于资源DLL中时如何使用TaskDialog()。我们需要包含资源的DLL的HINSTANCE。对于此示例,我们假设DLL已加载,因此我们只需要在此处检索句柄。此方法因类库而异;以下是您可以在ATL、WTL和MFC中调用的函数

  • ATL在VC 6和WTL中使用全局CAppModule变量:_Module.GetResourceInstance()
  • ATL在VC 7及更高版本中:_AtlBaseModule.GetResourceInstance()
  • MFC在VC 6中:AfxGetResourceHandle()
  • MFC在VC 7及更高版本中:AfxGetResourceHandle()AfxFindResourceHandle()

首先,让我们用资源ID替换硬编码字符串

HINSTANCE hinst = _Module.GetResourceInstance();  // this is the WTL method
 
  hr = TaskDialog ( m_hWnd, hinst,
                    MAKEINTRESOURCE(IDS_SAMPLEDLG_TITLE),
                    MAKEINTRESOURCE(IDS_SAMPLEDLG_HEADER),
                    MAKEINTRESOURCE(IDS_SAMPLEDLG_BODY),
                    TDCBF_YES_BUTTON|TDCBF_NO_BUTTON,
                    TD_INFORMATION_ICON, &nClickedButton );

最后,让我们向对话框添加自定义图标

HINSTANCE hinst = _Module.GetResourceInstance();  // this is the WTL method
 
  hr = TaskDialog ( m_hWnd, hinst,
                    MAKEINTRESOURCE(IDS_SAMPLEDLG_TITLE),
                    MAKEINTRESOURCE(IDS_SAMPLEDLG_HEADER),
                    MAKEINTRESOURCE(IDS_SAMPLEDLG_BODY),
                    TDCBF_YES_BUTTON|TDCBF_NO_BUTTON,
                    MAKEINTRESOURCE(IDI_TD_SAMPLE_ICON),
                    &nClickedButton );

这是带有自定义图标的最终对话框

就是这么简单!虽然TaskDialog()易于使用,但对话框仍然比消息框复杂不了多少。在下一篇文章中,我将介绍TaskDialogIndirect(),它具有更多的功能和更多的UI特性。

使用示例应用程序

本文的演示项目是一个任务对话框构建器。您可以输入要在标题、标题和正文区域显示的文本,以及按钮和可选图标

然后,应用程序将使用这些参数调用TaskDialog(),以便您可以实际看到对话框

进一步阅读

版权和许可

本文是受版权保护的材料,©2006 Michael Dunn。我知道这并不能阻止人们在网上到处复制它,但我必须说出来。如果您有兴趣翻译本文,请给我发电子邮件告知。我不认为会拒绝任何人翻译的许可,我只是想知道翻译情况,以便在此发布链接。

本文附带的演示代码已发布到公共领域。我将其以这种方式发布,以便代码能让所有人受益。(我不会将本文本身设为公共领域,因为只在CodeProject上提供本文有助于提高我个人的知名度和CodeProject网站的流量。)如果您在自己的应用程序中使用演示代码,发送电子邮件告知我将受到赞赏(只是为了满足我对人们是否受益于我的代码的好奇心),但并非必需。在您自己的源代码中注明出处也受到赞赏,但并非必需。

修订历史

  • 2006年12月12日:文章首次发布。
  • 2006年12月26日:内容无更改,仅更新了系列导航链接。

系列导航:« 使用新的Vista文件对话框 | 使用TaskDialogIndirect构建获取用户输入的对话框 »

© . All rights reserved.