在软件开发中,创建一个进度对话框可能是一个挑战。尽管可以重用现有的对话框,但它可能看起来不是想要的样子,或者很难集成到代码中。幸运的是,IE 5为提供了一个解决方案,不需要再构建对话框或编写处理取消按钮的代码了!
BROWSEUI.DLL文件实现了一个名为IProgressDialog的COM接口,它提供了一个看起来像资源管理器和SHFileOperation()显示的对话框。
进度对话框具有以下特点:
AVI文件应该是272x60大小,并受到动画公共控件的常规限制。如果没有自己的AVI文件,MSVC附带了一些示例文件(在CD上的\common\graphics\avis目录中),或者可以打开shell32.dll的资源编辑器并从中获取一个。(如果想知道,在上面的屏幕截图中从Internet FastFind获取了AVI。)
尽管文档指出可以从对话框中移除最小化按钮,但这似乎在Windows 2000的2195版本中也是有问题的。对话框将始终有一个最小化按钮(至少在微软修复它之前)。
由于COM方法有几个标志和保留参数,编写了一个薄薄的MFC包装类CSHProgressWnd,这使得代码更加易读。MFC类不是从CWnd派生的,因为COM接口不直接提供对进度窗口的访问。这意味着甚至可以在控制台应用程序或其他不使用CWnd框架的情况下使用包装器。
如果在想名字,在类名中加入了"SH",因为MSDN指出IProgressDialog接口实际上是shell32.dll的一部分(并且只在Windows 2000上可用!),使用"SH"来表示它是一个shell特性。后来发现对话框在旧版本的Windows上也能很好地工作,但那时已经完成了代码。
CSHProgressWnd构造函数创建一个IProgressDialog对象。在一个正常工作的系统上,这总是会成功的。然而,如果想再次检查一切是否正常工作,可以调用IsValid()函数。注意,必须在使用CSHProgressWnd对象之前初始化OLE(例如,使用AfxOleInit())。
CSHProgressWnd析构函数销毁对话框并释放COM接口。
调用这些函数来确定对话框的外观。
void SetTitle ( LPCTSTR szTitle )
设置进度对话框标题栏中显示的文本。
void SetAnimation ( HINSTANCE hinst, UINT uRsrcID )
void SetAnimation ( UINT uRsrcID )
指定一个包含将在对话框中显示的AVI的资源。第一个函数接受包含资源的模块的HINSTANCE。第二个形式使用AfxGetResourceHandle()的返回值作为模块。
void SetCancelMessage ( LPCTSTR szMessage )
设置用户点击取消按钮时在第三行显示的文本。
void SetCalculateTime ( bool bCalculate = true )
设置进度对话框是否在第三行显示剩余时间的估计。如果不调用SetCalculateTime(),对话框默认显示剩余时间。
void SetAllowMinimize ( bool bAllow = true )
设置进度对话框是否包含最小化按钮。如果不调用SetAllowMinimize(),对话框默认包含一个最小化按钮。注意:调用SetAllowMinimize(false)不会移除最小化按钮;这似乎是对话框实现中的一个错误。
void SetShowProgressBar ( bool bShow = true )
设置进度对话框是否显示进度条。如果不调用SetShowProgressBar(),对话框默认包含一个进度条。
进度对话框可以是模态的或非模态的。调用这两个函数中的一个来显示对话框。
HRESULT ShowModal ( CWnd* pwndParent )
将对话框作为模态对话框显示。pwndParent是指向父窗口的指针。使用SUCCEEDED()宏测试返回值以确定对话框是否成功创建。如果对话框未创建,返回值是IProgressDialog::StartProgressDialog()方法返回的错误。
HRESULT ShowModeless ( CWnd* pwndParent )
与ShowModal()相同,但进度对话框是非模态的而不是模态的。
void SetLineText ( DWORD dwLine, LPCTSTR szText, bool bCompactPath = false )
设置对话框中的三行文本之一。dwLine可以是1、2或3。第1行和第2行出现在AVI和进度条之间,第3行出现在进度条下方。如果让对话框计算剩余时间(通过调用SetCalculateTime(true)),对话框使用第3行显示估计的剩余时间,并且该行对SetLineText()不可用。如果正在显示文件名或路径,请为第三个参数传递true,以便对话框缩短路径以适应对话框。
void UpdateProgress ( DWORD dwProgress, DWORD dwMax )
void UpdateProgress ( DWORD dwProgress )
UpdateProgress()设置对话框的进度指示器。第一个函数形式设置当前和最大进度值。这些可以是,例如,0和100,但确切的值由决定。必须第一次调用第一个形式,然后只要最大进度值不变,就可以调用第二个形式。如果需要,可以自由地改变最大值,只要在最大值变化时调用第一个形式。
void UpdateProgress ( ULONGLONG u64Progress, ULONGLONG u64ProgressMax )
void UpdateProgress ( ULONGLONG u64Progress )
这两个函数的工作方式与前两个相同,只是它们接受64位数字而不是DWORD。
bool HasUserCanceled()
应该定期调用HasUserCanceled(),如果函数返回true,则退出。
void EndDialog()
调用EndDialog()关闭进度对话框。CSHProgressWnd析构函数也会在对话框仍然可见时关闭对话框。
void ResetTimer()
void CMyDialog::ProcessSomeStuff()
{
CSHProgressWnd dlg;
const DWORD dwMax = 100;
TCHAR szMsg[256];
dlg.SetTitle ( _T("Hang on a sec...") );
dlg.SetAnimation ( IDR_PROGRESS_AVI );
dlg.SetCancelMessage ( _T("Cancelling this operation...") );
dlg.SetLineText ( 1, _T("Unzipping files...") );
if ( FAILED( dlg.ShowModal ( this ) ) )
return;
dlg.UpdateProgress ( 0, dwMax );
for ( DWORD dwProgress = 0; dwProgress < dwMax && !dlg.HasUserCanceled(); dwProgress += 5 )
{
DoSomeSlowProcessing();
wsprintf ( szMsg, _T("I'm %lu%% done"), dwProgress );
dlg.SetLineText ( 2, szMsg );
dlg.UpdateProgress ( dwProgress );
}
dlg.EndDialog();
}