📄 9.6.2 在状态栏的窗格中创建.txt
字号:
成PostMessage函数,然后运行一下 Style程序,将会看到在程序的状态栏上终于显示出了进度栏,
如图9.42所示。
图 9.42在状态栏上显示进度栏
我们可以看到这时的进度栏是用一些小方块来表示当前位置,如果想得到连续的、平滑的显示效果,
在创建进度栏对象时,就需要设置 PBS SMOOTH类型,之后,将得到如图 9 .43所示的效果。
但是,这个进度栏还有一些缺陷,当 S tyle程序窗口尺寸发生变化后,会发现进度栏显示的位置发
生了错误,如图 9 .44所示。可以看到,这时的进度栏并不是如我们所希望的那样在指定的窗格中
显示。发生这种情况主要是因为当程序窗口尺寸区域发生变化时,窗口上的状态栏的窗格尺寸区域
也会随之变化,因此,上述 On Progress代码巾最早获得的窗格区域就不正确了,所以就看到进度
栏与窗格发生了脱离。
图 9.44程序,窗口尺寸发生变化,进度栏位置错位
为了改正这种情况,我们就需要在程序窗口尺寸区域发生变化时,重新去获取索引为 2的状态栏窗
格区域,然后将进度栏移动到这个区域中。我们知道,当窗口尺寸发生变化时,窗口会发生一个重
绘,于是会发生一个 WM PAINT消息。因此,我们只需要在响应这个消息的函数中,重新去获取索引
值为 2的状态栏窗格区域,然后将进度栏移动到这个区域中就可以了。下面我们为 CMainFrame类添
加 WM PAINT消息的响应函数,然后在此函数中添加如例 9-29所示代码。
例 9-29
void CMainFrame : : OnPaint()
CPaintDC dc(this); // device context for paint工 ng
// TODO: Add your message handler code here
CRect rect ;
m wndStatusBar . GetItemRect(2 , &rect) ;
m-PI' ogress . Create(WS一CHILD I WS_V工 S工 BLE I PBS_SMOOTH ,
rect , &m_ wndStatusBar , 123) ;
m-progress . SetPos(50) ;
// 00 not call CFrameWnd : :OnPaint() for pa工ntìng messages
这时,先前在CMainFrame类的OnCreate函数添加的发送自定义消息的那条代码就不需要了,因为当
窗口第一次显示时,就会调用 OnPaint函数,这样就得到了窗格的区域,并创建进度栏。因此,把
OnCreate函数中调用PostMessage函数的那条代码注释起来,让程序不再发送UM PROGRESS这条自定
义消息。这时,并不需要把OnProgress函数中己有代码注释起来,因为对自定义消息来说,只有程
序自己主动发送这些消息,而系统并不会发送这些消息。因为我们己经把发送UM PROGRESS这条消息
的代码注释起来了,所以这个自定义消息的响应函数OnProgress就永远没有执行的机会,也就不需
要把它的代码注释起来。
读者可以运行一下此时的 Style程序,会发现程序初始显示时进度栏显示的位置是正确的,但当程
序窗口尺寸发生变化后,程序会弹出一个非法操作提示对话框。如图9.45所
图 9.45非法操作对话框
这个问题的发生实际上与前面第7章中介绍动态按钮的创建时发生的错误是一样的,当程序窗口尺寸
发生变化时,会发送一个WM PAINT消息对这个窗口进行重绘。于是,程序就会调用 OnPaint这个消
息响应函数。但是,这时程序己经创建了一个进度栏,井与 m_progress对象相关联。这里再一次创
建进度栏对象并进行关联,当然就会出错。为了解决这个问题,在程序中需要进行一个判断,如果
进度栏还没有被创建,就创建它;如果已经创建了,就把进度栏移动到目标矩形区域中。至于实现这
种判断的方法,前面曾介绍过多种,其中最简单的方法就是直接判断m_progress对象的窗口句柄,
如果该句柄没有值,即为NULL时,就说明该对象还没有被创建,于是就创建进度栏,并与m_progress
对象相关联:否则,就应该把进度栏移动到目标矩形区域中。为了移动一个窗口,可以调用CWnd类的
成员函数: MoveWindow来实现。因此,修改后的OnPaint函数代码如例9-30所示。
例9-30
void CMainFrarne : :OnPaint() CPaintOC dc(this) ; 11 device context for painting 11 TOOO :
Add your message handler code here
CRect rect ;
m_wndStatusBar.GetItemRect(2,&rect) ;
if(!m-progress .m_hWnd)
m-progress.Create(WS_CH工LO I WS_VIS工BLE I PBS_SMOOTH , rect , &m_wndStatusBar , 123) ;
else
m_progress .MoveWindow(rect) ;
m-progress . Setpos(50) ;
// 00 not call
CFrameWnd : :OnPaint() for pa工nting messages
读者可以再次运行 Style程序,将会发现当程序窗口尺寸发生变化时,进度栏都能正确地显示。因
为每次窗口尺寸发生变化时,都会发送一个WM PAINT消息,而在这个消息的响应函数 COnPaint)中,
再次得到了指定窗格的矩形区域。并且判断m_progress对象的窗口句柄己经有值了,所以程序就把
进度栏移到这个区域中。
提示::也可以调用 SetWindowPos函数设直进度栏的位直,这个函数的使
用比较麻烦,没有MoveWindow函数简单。但前者的功能要多些,例如它可以将程序窗口设直为顶层
窗口。
下面,我们要让新建的这个进度栏"动起来",即在进度栏上以某种显示方式不断增加当前位置,这
可以通过CProgressCtrl类的Steplt成员函数来完成。该函数将使进度栏控件的当前位置按照一定的
步长前进。至于每次前进的步长则可以通过CProgressCtrl类的另一个成员函数: SetStep来设置。
一旦调用这个函数设置了一个步长,随后的Steplt函数就将按照这个步长前进。另外,对于进度栏
来说,还可以设置宫的范围,这可以通过调用 CProgressCtrl类的 SetRange这一成员函数来实现。
默认情况下,范围的最小值是0,最大值是 100。一般来说,应该根据该进度栏所实现的功能来设置
它的范围。例如,要实现一个软件安装的进度控制,则可以根据软件安装的进度来设置进度栏的范
围;如果要实现一个播放影片的进度控制,则可以根据影片的播放时间来设置进度栏的范围。
让我们回到 Style程序,让进度栏的当前位置每隔一秒钟就前进一步,也就是在 CMainFrame类的
OnTimer函数中添加例9-3 1所示代码中加灰显示的那行语句。
void CMainFrame : :OnTimer(UINT nIDEvent)
// TODO : Add your message handler code here and/ or call default
static int index=O ;
SetClassLong(m_hWnd, GCL_HICON, (LONG)m_hIcons[工口dex1 ) ;
index=++index宅3 ;
CTime t=CTime::GetCurrentT工me () ;
CString str=t.Format("宅H :毡M:毡S" ) ;
CClientDC dc(this);
CSize sz=dc . GetTextExtent(str);
m wndStatusBar.SetPaneInfo(1,IDS_TIMER, SBPS_NORMAL, sz.cx);
m_wndStatusBar.SetPaneText(1 , str);
m-progress.Steplt();
CFrameWnd::OnTimer(nIDEvent);
Build并运行 Style程序,将会看到在状态栏上创建的进度栏的当前位置一点一点地平滑地向前行
进,当到达进度栏的最大范围后,又从头开始一点→点地前进。这是为进度栏设置了 PBS_SMOOTH
类型时的运行效果,如果没有设置这种类型,程序运行时,将会发现此时的进度栏是以一个小块一
个小块的方式前进,因为这时一个块向前走的距离比较大,所以进度栏在前进过程中需要等待片刻,
直到凑齐→个小块的距离之后才向前走一个块。在实际编程时,读者可以根据自己的需要选择这两
种类型的进度栏中的一种来使用。
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -