VC技巧:在程序的状态栏中实现进度条(2)
虽然子窗口控件通常都是放在父窗口能绘制的区域的最上面,但这样做在绘制方面是有一定风险的。在隐藏/显示进度控制时尤其如此,这时候会出现两个问题:第一,因为进度指示器显示在状态栏的第一个窗格位置,所以如果进度条指示器显示时已经显示有状态信息,那么进度指示器和状态信息文本就会有冲突,相互干扰。之所以会这样,是因为进度控制假设其绘制背景是干净的,并且只绘制进度控制的着色部分。解决这个问题最简单的方法是调用CStatusBar::SetWindowText(NULL)函数在显示进度指示器之前打扫一下环境卫生,清除以前的文本。
对于状态栏来说,SetWindowText函数的作用是设置状态栏第一个窗格的文本。反之,当调用OnProgress(0)清除进度控制时也存在类似的问题,CProgStatusBar::OnProgress 隐藏进度控制后,状态栏第一个窗格该显示什么信息呢?一般显示"就绪"或其它的提示信息。当应用程序不做任何事情时,MFC程序总是在这个位置显示资源串AFX_IDS_IDLEMESSAGE表示的文本,其缺省值为"就绪",当然读者朋友们可以在当前项目的RC文件中任意修改这个值,不管怎样,在MFC程序的状态栏中显示"就绪"信息很容易,需要作的就是在CProgStatusBar::OnProgress()函数中调用语句GetParent()->PostMessage(WM_SETMESSAGESTRING,AFX_IDS_IDLEMESSAGE)向父窗口发送一个WM_SETMESSAGESTRING消息就可以了,需要注意的是,使用消息WM_SETMESSAGESTRING时必须包含它的定义文件"afxpriv.h",否则程序会报告编译错误。
上述CprogStatusBar类实现了状态栏中包含进度条控件,该类的使用方法很简单,首先在应用程序的CmainFrame类中用CProgStatusBar代替CStatusBar声明实例,然后在任何想要显示进度控制指示的地方调用CProgStatusBar::OnProgress。本例中定义了一个消息MYWM_PROGRESS,它将进度条当前的进度作为WPARAM参数传递到CProgStatusBar::OnProgress()函数。
经过上述处理,想要使用进度指示的任何对象都可以通过发送一个消息到主框架来调用状态栏进行进度条的显示。例如,在例子程序中,文档的Serialize()函数在加载文本文件时,利用Sleep()函数仿真耗时加载,每隔150毫秒报告一次进度状态。如果你不想从文档发送Windows消息,可以用MFC的视图更新机制来做。你可以发明一个"暗示"代码以及一个小结构来保存进度百分比数据,并通过向框架发送MYWM_PROGRESS消息调用暗示信息。这是从文档到视图/框架传递进度控制信息的最省事的方式。
二、编程步骤
1、 启动Visual C++6.0,生成一个单文档应用程序prgsbar,项目的视图类的基类选择CEdit类;
2、 在程序的Resource.h文件中添加自定义消息的定义:
#define MYWM_PROGRESS (WM_USER+1)
3、 在程序的主框架窗口CMainFrame类的头文件中声明MYWM_PROGRESS的消息响应函数afx_msg LRESULT OnProgress(WPARAM wp, LPARAM lp),在该类的实现中添加消息映射ON_MESSAGE(MYWM_PROGRESS,OnProgress);
4、 将CMainFrame类中的工具条对象改为CProgStatusBar m_wndStatusBar;
5、 重载CPrgsbarDoc::Serialize(CArchive& ar)函数,用来处理读取文件时的进度条仿真;
6、 添加代码,编译运行程序。
三、程序代码
////////////////////////////////////////////CprogStatusBar类的头文件;
// Status bar with progress control.
class CProgStatusBar : public CStatusBar {
public:
CProgStatusBar();
virtual ~CProgStatusBar();
CProgressCtrl& GetProgressCtrl() {
return m_wndProgBar;
}
void OnProgress(UINT pct);
protected:
CProgressCtrl m_wndProgBar; // the progress bar
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnSize(UINT nType, int cx, int cy);
DECLARE_MESSAGE_MAP()
DECLARE_DYNAMIC(CProgStatusBar)
};