在利用MFC
编制应用程序尤其是涉及到数值分析与模拟程序时,要进行大量的数值运算,如在屏幕上显示三维、二维图形和图像就需要进行数据拟合、样条以及插值等算法,而且为了保证精度,运算时数据点一般还采用浮点甚至双精度浮点数,这样应用程序就需要大量的CPU
时间来完成相应的工作,一般持续几分钟、几十分钟甚至更多的时间。如果应用程序不输出一些信息的话,常常会让人误解系统是不是死掉了。因此Windows
系统提供了一个函数:
LoadCursor( UINT nIDResource ) const ;
通过这个函数可以改变鼠标的形状为沙漏来表明系统正处于一个耗时的过程。但是一般而言这种改变很容易让人忽略,并且不知道当前进程完成了多少,还剩下多少。
在MFC 中,提供了进程条控件CProgressCtrl
类,利用该类可以很方便地显示进程的完成状况。为了显示当前进程的完成状况,用进程条控件CProgressCtrl
类来实现有很多种方法,如采用多线程编程方法,通过线程通信来显示,也可以在同一线程当中,采用含进程条控件CProgressCtrl
类的无模式对话框来显示。但是这几种方法都比较复杂且不方便,需要占用一定的系统资源,状态显示响应也不是十分迅捷。
Windows
应用程序一般在其底部有一个小条通称状态条。状态条的右边是几个可以动态增加或删除的状态格,MFC
中提供了状态条控件CStatusBar
类来完成状态格的管理。因此我们可以采用在应用程序的状态条中增加一个进程条状态格的方法来显示当前进程任务的完成状态。显然相比于前面所述的方法,这种方法比较方便且容易实现,不占用系统资源,状态显示响应十分迅捷。下面具体阐述实现方法:
用AppWizard 创建一个工程文件pBar,单文档应用或者多文档应用皆可。其他选项均可采用缺省。
在Visual Studio 的工作台,选择“View"菜单下的“Resource
Symbols"菜单命令,弹出对话框后按下“New"
按钮,增加一条新的符号ID_INDICATOR_PROGRESS_PANE 并采用系统分配的缺省ID
值,如图1 所示。
在MainFrm.cpp
文件的状态条状态格指示数组(紧接在消息映射代码段后)中增加资源符号ID_INDICATOR_PROGRESS_PANE
或者其ID 值。注意如果将符号ID_INDICATOR_PROGRESS_PANE
放在数组的最后则表明进程条状态格将在状态条的最右边,如果你将符号ID_INDICATOR_PROGRESS_PANE
放在数组的前面则表明进程条状态格将在状态条的最左边,如果将符号ID_INDICATOR_PROGRESS_PANE
放在数组的中间则表明进程条状态格将在状态条的中间。具体参见如下代码:
static UINT indicators[] =
{
ID_SEPARATOR, // status line indicator
ID_INDICATOR_PROGRESS_PANE,
// means the progress pane in far left.
ID_INDICATOR_CAPS,
ID_INDICATOR_NUM,
ID_INDICATOR_SCRL,
};
打开资源编辑器,选择字符串表,单击鼠标右键,选择“New
String"命令(或者通过工作台的“Insert"菜单选择“New
String"命令),弹出字符串属性编辑对话框如图2 所示,在ID
栏键入符号ID_INDICATOR_PROGRESS_PANE,在Caption
编辑栏键入空格。注意空格的多少将决定状态条中进程状态格的长度,具体见图2。
在头文件MainFrm.h 中,增加两个变量:一个为CProgressCtrl 控件设为m_Progress;另一个为逻辑步尔变量设为m_bCreated,该变量用来标志CProgressCtrl
控件是否成功创建。
在源文件MainFrm.cpp 的OnCreate() 函数中,初始化m_bCreated 为FALSE。如下所示:
m_bCreated = FALSE;
模拟一个耗时过程函数OnSomeLongProcess()
来演示状态条中的进程状态格。这里简单地采用睡眠函数来模拟一个耗时过程。函数代码如下:
void CMainFrame::OnSomeLongProcess()
{
RECT MyRect;
// substitute 1 with the zero -based index of
your status bar pane. For example, if you put your
// pane first in the indicators array,
you put 0, second you put 1, etc.
m_wndStatusBar.GetItemRect(1, &MyRect);
if (m_bCreated == FALSE)
{
//Create the progress control
m_Progress.Create(WS_VISIBLE|WS_CHILD,
MyRect, &m_wndStatusBar, 1);
m_Progress.SetRange(0,100);.
//Set the range to between 0 and 100
m_Progress.SetStep(1); // Set the step amount
m_bCreated = TRUE;
}
// Now we'll simulate a long process:
for (int I = 0; I < 100; I ++)
{
Sleep(20);
m_Progress.StepIt();
}
}
状态条中的进程状态格创建成功后,如果应用程序主窗口尺寸发生变化,进程状态格的大小不会自动适应主窗口的变化,因此需要重载主窗口的OnSize()函数。通过ClassWizard
在主窗口中增加WM_SIZE 消息映射函数,如图3 所示。
具体的源代码如下:
void
CMainFrame::
OnSize(UINT nType, int cx, int cy)
{
CFrameWnd::OnSize(nType, cx, cy);
// TODO: Add your message handler code here
if(m_bCreated == TRUE){
RECT rc;
m_wndStatusBar.GetItemRect(1, &rc);
// Reposition the progress control correctly!
m_Progress.SetWindowPos( &wndTop, rc.left, rc.top, rc.right
-rc.left,rc.bottom -rc.top, SWP_SHOWWINDOW);
}
}
打开资源编辑器,在“查看”菜单下增加“Test"菜单命令,ID
设为ID_TEST。然后利用ClassWizard 增加一条消息映射函数OnTest(),代码如下:
void CMainFrame::OnTest()
{
// TODO: Add your command handler code here
OnSomeLongProcess();
}
在完成所有以上步骤后,编译、运行程序,选择“查看”菜单下的“Test"菜单命令就会看到状态条中的进程状态格的进程显示情况。
上面我们用一个简单的睡眠函数模拟了耗时过程中,状态条的进程状态格的显示情况。在实际应用中我们只需将源码中OnSomeLongProcess()
函数替换成相应的耗时过程函数即可。