📄 9.6.2 在状态栏的窗格中创建.txt
字号:
9.6.2 在状态栏的窗格中创建进度栏
下面,我们要实现在程序状态栏的窗格中显示进度栏。这时,首先需要获得该窗格的区域,然后将
这个区域的大小作为进度栏的大小。为了获得窗格的区域,可以利用 CStatusBar类的 GetPaneInfo
成员函数来完成。该函数的原型声明如下所示 :
void GetltemRect(int nindex, LPRECT lpRect ) const ;
其中,第一个参数( nlndex )指定窗格索引:第二个参数 OpRect)指定用来接收指定索引的窗格的矩
形区域。
因此,在 Style程序的 CMainFrame类的 OnCreate函数中,对上面。和 @符号所示的创建进度栏的
代码进行修改,以实现在状态栏的第三个窗格 ( Il. P IDS_PROGRESS资源 D指定的窗格,其索引为
2)上显示进度栏,此时,状态栏对象将作为进度栏的父窗口。修改后的代码如例如25所示。
例9-25
1. CRect rect ;
2. m_wndStatusBar.GetItemRect(2 , &rect);
3. m-progress . Create(WS_CHILD | WS_VISIBLE , rect , &m_wndStatusBar , 123) ;
4. m-progress . SetPos(50) ;
Build并运行Style程序,读者将会发现在状态栏上并未创建进度栏。为了找到原因,我们在上述例
如21所示代码段的第三行代码处设置一个断点,并调试运行Style程序。当程序执行到这个断点时,
利用VC++提供的Watch窗口(在调试状态下可利用【View\Debug Windows\Watch】菜单命令打开此窗
口)查看rect变量的当前值,如图9.41所示。可以看到,这时, rect对象的left和right值都是-17。
这明显不是一个正常的矩形区域,说明我们没有得到状态栏上指定窗格的区域。因此,随后创建进
度栏的操作自然也就失败了。
这里之所以没有得到状态栏上指定窗格的矩形区域,是因为此时状态栏的初始化工作,即对窗格的
摆放操作还没有完成。我们知道, CMainFrame类的OnCreate函数是在响应框架窗口的WM CREATE消
息时调用的,只有在这个函数执行完成之后,才能够获得窗口状态栏上窗格的矩形区域。遵照这种
思路,我们可以试试这种方法是否可行:自定义一个消息,然后在CMainFrame类的OnCreate函数中在
其返回之前发送这条消息,最后在这个自定义消息的响应函数中获得状态栏上窗格的矩形区域。
我们知道,在Windows中,所有的消息都是用一个特定的整数值来表示的,为了避免我们自定义的这
条消息与其他己有消息值发生冲突,应该利用Windows提供的一个常量: WM USERo小于这个常量的值
都是Windows系统保留的,我们自定义的消息只需要大于这个常量就可以了。于是,在定义自定义消
息时,通常都是用WM USER加上一个数值,这个值可由编程人员自行决定,但是要注意最后表示消息
的数值不要超过Ox7FFFF(关于消息数值的范围和它们表示的含义,读者可以在MSDN的索引页面中查
看WM USER的帮助文档)。本例中,加上值1就可以了。因此,在Style程序中,在CMainFrame类的头
文件中定义一条自定义的消息,定义代码如下所示:
#define UM_PROGRESS WM_USER+l
目标: Windows消息用 WM_为前缀表示,我们自定义的消息最好用 UM_
为前缀表示,表示用户消息 ( User Message )。但这并不是必须要这样做。下面,为这条自定义消
息添加消息响应函数原型的声明,方法是在 CMainFrame类的头文件中,在两个 AFx_MSG注释宏的
外面添加这条声明语句,结果如例如26所示。例 9-26
// Generated message map functions
protected :
// {{AFX_MSG(CMainFrame)
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct) ;
afx_msg void OnTimer(UINT nIDEvent) ;
afx_ msg void OnTest() ;
afx_msg void OnViewNewtoolbar();
afx_msg void OnUpdateViewNewtoolbar( C CmdUI* pCmdUI) ;
// }}
AFX_MSG
afx_msg void OnProgress();
DECLARE_ MESSAGE_MAP()
这个消息响应函数 C OnProgress )的定义与前面介绍的命令消息的响应函数是相同的,如果在发送
该消息时,还需要附带发送一些数据,在声明这个响应函数时,就应该让其带有与消息相关的两个
附加参数 C wParam和 lParam ) ;否则,这个响应函数可以没有参数。
接下来就是为这条自定义消息添加消息映射,前面介绍的命令消息是用 ON-COMMAND宏将消息与消息
响应函数关联起来,而对于自定义消息来说,使用的是 ON_ MESSGE宏来实现这一功能。因此,在
CMainFrame类的源文件中,在消息映射表的两个注释宏之外,添加 UM一PROGRESS这一自定义消息的
消息映射,结果如例 9 -27所示。
例 9-27
BEGIN_MESSAGE_MAP(CMainFrame , CFrameWnd) 11 {{AFX_MSG_MAP(CMainFrame) ON_WM_CREATE ()
ON_WM_TIMER ( )
ON_COMMAND(IDM_TEST, OnTest)
ON_COMMAND(IDM_VIEW_NEWTOOL , OnViewNewtool)
ON_UPDATE_COMMAND_UI(IDM_VIEW_NEWTOOL, OnUpdateViewNewtool)
ON_WM_PAINT ( )
// }}AFX_ MSG_MAP
ON_MESSAGE (UM_PROGRESS, OnProgress)
END_MESSAGE_MAP()
最后,当然就是添加这个消息响应函数的实现,具体代码如例 9 -28所示。 例 9-28
void CMainFrame : : OnProgress()
{
CRect rect ;
m_wndStatusBar .GetltemRect(2 , &rect) ;
m-progress .Create(WS_CHILD | WS_VISIBLE , rect , &m_wndStatusBar , 123) ;
m_progress .SetPos(50) ;
然后在CMainFrame类的 OnCreate函数中将先前创建进度栏的代码(即上述例 9-25所示代码段)注释
起来,然后在其后添加下面这条语句,即利用 SendMessage函数发送 UM PROGRESS这个自定义的消
息:
SendMessage(UM_PROGRESS) ;
Build并运行Style程序,结果,发现在状态栏上仍没有看到进度栏控件。为了了解程序的运行过程,
我们可以在Style程序中设置三个断点,一个是在CMainFrame类的OnCreate函数中刚刚添加的
SendMessage函数处,一个是位于这条代码下面的retum语句,第三个断点设置在OnProgress函数的
定义处。然后调试运行Style程序,程序首先会暂停在SendMessage函数处:继续执行,程序将会暂停
在 OnProgress函数的定义处:再继续执行,程序将会暂停在OnCreate函数的retum语句处。也就是说,
在OnCreate中调用SendMessage函数发送 UM_PROGRESS后,程序就会调用这个消息的响应函数来处
理。在这个响应函数执行完成之后,又返回到OnCreate函数中执行SendMessage函数的下一条语句,
即 retum语句。我们可以发现,实际上,这时就相当于把创建进度栏的代码直接放在 OnCreate函数
中,与上面的实现方式是相同的,因此这时也不能获得窗格的矩形区域,所以,进度栏没有创建成
功。造成这种情况的主要原因是SendMessage函数发送消息的机制,它是直接把消息发送给消息响应
函数,由消息响应函数处理完成之后, SendMessage函数才返回。这就造成了当消息发送之后,程
序流程跳转到相应的消息响应函数中,执行完成之后再返回到 SendMessage函数的下一条语句继续
执行。因此这里不能使用 SendMessage这个函数,应该使用PostMessage函数。 PostMessage函数是
把消息放到消息队列中,然后立即返回,之后程序通过 GetMessage函数按顺序把消息一条一条地取
出来。对于本例来说, OnCreate
是WM CREATE消息的响应函数,在对这个消息处理完毕后(即OnCreate函数执行完毕), MFC底层代码
调用 GetMessage函数才从消息队列中取出UM PROGRESS这条自定义消息,此时才轮到 OnProgress
函数去执行,这时因为 OnCreate函数已经执行完成,因此状态栏的初始工作也己经全部完成,就可
以得到状态栏窗格的矩形区域,从而就可以创建进度栏了。读者可以把刚才那条SendMessage函数换
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -