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






4.87/5 (19投票s)
2006年12月12日
7分钟阅读

102082

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_BUTTON
、TDCBF_YES_BUTTON
、TDCBF_NO_BUTTON
、TDCBF_CANCEL_BUTTON
、TDCBF_RETRY_BUTTON
、TDCBF_CLOSE_BUTTON
。按钮的组合没有限制;您可以在此参数中设置任意数量的标志。如果传递0,则默认行为是只显示一个“确定”按钮。请注意,除非传递了
TDCBF_CANCEL_BUTTON
,否则无法使用Esc键或Alt+F4键关闭对话框。 pszIcon
- 要在任务对话框中显示的图标的资源ID。与字符串参数一样,您必须在ID上使用
MAKEINTRESOURCE
或MAKEINTRESOURCEW
宏。您也可以传递以下预定义值之一来使用系统图标:TD_ERROR_ICON
、TD_WARNING_ICON
、TD_INFORMATION_ICON
、TD_SHIELD_ICON
。TD_SHIELD_ICON
显示UAC盾牌(),并且只应用于指示用户需要提升权限才能执行管理任务的情况。您也可以传递
NULL
,如果您不想要任何图标。 pnButton
- 指向
int
的指针,该指针设置为以下值之一,以指示用户单击了哪个按钮:IDOK
、IDYES
、IDNO
、IDCANCEL
、IDRETRY
、IDCLOSE
。如果在dwCommonButtons
中传递了TDCBF_CANCEL_BUTTON
,则用户按下Esc或Alt+F4时,*pnButton
将设置为IDCANCEL
。如果TaskDialog()
失败,则该值将设置为0。如果不需要知道单击了哪个按钮,则可以将此参数传递为NULL
。
TaskDialog()
的返回值是一个HRESULT
,指示函数是否成功。如果无法加载资源或在内存不足的情况下,它可能会失败。
如果pszWindowTitle
为NULL
,则使用可执行文件的文件名作为标题文本。如果不需要在对话框中显示某段文本,则pszMainInstruction
或pszContent
可以为NULL
。此外,pszMainInstruction
和pszContent
可以是多行字符串;在字符串中插入换行符('\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()
,以便您可以实际看到对话框
进一步阅读
- 构建您的第一个TaskDialog(第2部分)
- MSDN上有关于新的Vista UI指南的一些冗长的页面;对于任务对话框,需要熟悉的是文本和语气。
版权和许可
本文是受版权保护的材料,©2006 Michael Dunn。我知道这并不能阻止人们在网上到处复制它,但我必须说出来。如果您有兴趣翻译本文,请给我发电子邮件告知。我不认为会拒绝任何人翻译的许可,我只是想知道翻译情况,以便在此发布链接。
本文附带的演示代码已发布到公共领域。我将其以这种方式发布,以便代码能让所有人受益。(我不会将本文本身设为公共领域,因为只在CodeProject上提供本文有助于提高我个人的知名度和CodeProject网站的流量。)如果您在自己的应用程序中使用演示代码,发送电子邮件告知我将受到赞赏(只是为了满足我对人们是否受益于我的代码的好奇心),但并非必需。在您自己的源代码中注明出处也受到赞赏,但并非必需。
修订历史
- 2006年12月12日:文章首次发布。
- 2006年12月26日:内容无更改,仅更新了系列导航链接。
系列导航:« 使用新的Vista文件对话框 | 使用TaskDialogIndirect构建获取用户输入的对话框 »