📄 9.5状态栏编程.txt
字号:
9.5状态栏编程
应用程序窗口的最下方就是状态栏,如图9.30所示。
图 9.30状态栏
状态栏可以分为两部分,其中左边最长的那部分称为提示行,当我们把鼠标移动到某个菜单项或工
具按钮上时,该部分将显示相应的提示信息。例如当鼠标移动到 Style程序中【文件】子菜单下的
【保存】菜单项时,状态栏最左边的窗格将显示该菜单项的提示信息:"保存活动文档",如图9.31
所示。
图 9.31状态栏上的提示信息状态栏的第二部分是其右边的三个窗格,主要用来显示Caps Lock, Num
Lock和 Scroll
Lock键的状态,称为状态栏指示器。当在程序运行后按下CapsLock键,程序状态栏上这三个窗格中
左边第一个窗格将显示:"大写",如图9.32所示:当再次按下CapsLock键,该窗格上的字符串就消失
了。
图 9.32 Caps Lock键按下后的状态栏
在 Style程序中,状态栏对象也是在 CMainFrame类中定义的,在该类的头文件中有下面这行代码,
其中CStatusBar类就是与状态栏相关的MFC类:
CStatusBar m_wndStatusBar;
在CMainFrame类的OnCreate函数中可以看到如例9-18所示的这段代码。
例9-18
if ( !m_wndStatusBar .Create(this) || !m_wndStatusBar.Setlndicators(indicators ,
.
sizeof(indicatorsl /sizeof(UINT) ||
TRACEO("Failed to create status bar\n" ) ;
return -1; // fail to create
这段代码首先调用状态栏对象的Create函数创建状态栏对象,这个函数的原型声明如下所示:
BOOL Create ( CWnd* pParentWnd, DWORD dwStyle = WS_CHILD 1 WS_VISIBLE 1 CBRS_ BOTTOM, U
工NT nID = AFX_IDW_STATUS_BAR ) ;
其中,该函数的各个参数的意义如下所述:
. pParent飞νnd
指定状态栏的父窗口指针,通常都是指向程序的框架窗口对象。
. dwStyle
第二个参数指定状态栏的风格,除了标准的Windows窗口风格外,该参数还可以取表
9.3中所列的值。
表9.3状态栏风格
dwStyle 取值 说明
CBRS_TOP 控制条位于框架窗口的顶部
CBRS BOTTOM 控制条位于框架窗口的底部
CBRS NOALIGN 当父窗口大小发生改变时,控制条的位置不变
. nID
指定状态栏这个子窗口的ID,默认值是AFX_IDW_STATUS_BAR。
上述代码在创建状态栏之后,接着调用 SetInd i cators函数设置状态栏指示器,其中用到一个数
组参数: indicators,这个数组是在CMainFrame类源文件的前部定义的,定义代码如例9-19所示。
{例 9-19
static UINT indicators[] =
{
ID_SEPARATOR, // status line indicator
ID_INDICATOR_CAPS,
ID_INDICATOR_NUM,
ID_INDICATOR_SCRL,
};
可以看到,这个数组是一个静态的变量,数组元素是一些,第一个ID表示的是刚才看到的状态栏
最左边最长的那个窗格,即提示行,后面三个m分别是Caps Lock, Num Lock和ScrollLock键的状态
指示器。
SetIndicators函数的第二个参数用来设定indicators数组中元素的个数。
实际上, indicators数组中后三个E都是 MFC预先为我们定义好的字符串资源ID,读者可以在VC++
开发环境中打开Style工程的ResourceView选项卡,双击StringTable文件夹下的 String Table J
页,即可打开Style程序的字符串资源,在其中可以找到这三个ID的定义,如图9.33所示。
图 9.33状态栏使用的字符串资源D的定义
如果想要修改状态栏的外观,例如添加或减少状态栏上的窗格,则只需要在indicators数组中添加
或减少相应的字符串资源ID即可。本例想在Style程序的状态栏上显示当前系统的时间和一个进度条
控件,因此,首先需要为 Style程序增加两个新的字符串资源,其 B及Caption如表9.4所示。
表9.4新增的字符串资源
IDS_TIMER 时钟
IDS PROGRESS 进度栏
然后将这两个新的字符串资源ID添加到indicators数组中,结果如例9-20所示。
static UINT indicators[)
ID_SEPARATOR,
IDS_ TIMER ,
IDS_PROGRESS ,
ID_ INDICATOR_CAPS ,
ID_INDICATOR_NUM ,
ID_INDICATOR_SCRL,
Build井运行Style程序,结果如图9.34所示,可以看到程序的状态栏上多了两个窗格,其中一个显
示的是"时钟",另一个显示的是"进度栏",也就是刚才我们定义的字符串资源所表示的文本内容。 .
图 9.34新添两个窗格后的状态栏显示效果
接下来,我们希望在状态栏上显示"时钟"字符串的那个窗格上显示系统当前的时间,那么首先就需
要获取到系统当前时间,这需要用到一个新的MFC类: CTime,该类有一个静态的成员函数:
GetCurrentTime。该函数返回一个CTime类型的对象,表示系统当前的时间。然后,可以调用CTime
类的另一个成员函数: Format,对得到的CTime类型的时间对象进行格式化,得到一个包含格式化时
间的字符串。该函数常用的格式如表9.5所示(关于其他格式读者可查看MSDN中相关信息)。
表9.5 CTime类的Format函数常用的格式
%y 不带世纪的年号 00-99
%m 月份 1-12
%d 日期, 1-31
%H 以24小时制表示的时间, 0-23
%1 , 以 12小时制表示的时间, 1-12
为了将字符串显示到状态栏的窗格上,可以调用 CStatusBar类的 SetPaneText函数, 该函数的原
型声明如下所示:
BOOL SetPaneText(int nIndex, LPCTSTR lpszNewText , BOOL bUpdate = TRUE );
可以看到,这个函数有三个参数,其中,第一个参数是窗格在指示器数组 ( indicators ) 中的索
引,这里,根据前面 indi ca tor s数组的定义,可以知道 IDS TIMER表示的窗格在 indicators
数组中的索引是 1 ;
第二个参数就是在窗格上显示的文本 ;
第三个参数是 BOOL类型,如果其值为
TRUE,那么在设置窗格的文本之后,该窗格变成是无效的,当下次 WM PAINT消息发送后,该窗格将
发生重绘,该参数的默认值是 TRUE。
因此,为了在状态栏上显示"时钟"字符串的那个窗格上显示系统当前的时间,我们在 Style程序的
CMainFrame类的 OnCreate函数的后部,但要在其 return语句之前添加例如2 1这段代码。
例 9-21
CTime t=CTime : :GetCurrentTime() ;
CString str=t .Format( "%H :%M :%S " ) ;
m_wndStatusBar .SetPaneText(1 , str) ;
上述如例如2 1所示代码中,首先定义了一个 CTime类型的对象:t,接着调用 CTime类的静态函数
GetC Ul 11 entTime,运回一个表本系统当前时间的 CTime类型的对象。接下来,调用 CTime类的
Format函数得到一个表示时间的格式化字符串,其中 "%H ", "%D " 都是格式化符号,而" :"字符
将原样输出。然后,调用 CStatusBar对象的 SetPaneText函数把得到的时间字符串显示到状态栏的
相应窗格上。
Build并运行 Style程序,结果如图 9.35所示,可以看到这时在程序状态栏上显示了系统当前的时
图 9 .35状态栏上显不系统当前时间
如果在设置窗格的文本时不知道窗格的索引,此时可以利用 CStatusBar类的另一个成员函数 :
CommandToIndex,通过指定资源 E来得到相应的索引。这种情况下,上述如例如2 1所示代码应该变
成如例如22所示的这样。
i91J 9-22
CTime t=CTime : : GetCurrentTime ( ) ;
CString str=t . Format( "%H :%M :%S " ) ;
i ntindex=0 ;
index=m_wndStatusBar.CommandTolndex(IDS_TIMER) ;
m_wndStatusBar . SetPaneText(index,str) ;
读者可以测试一下这段代码,将会发现它与前面的代码实现的结果是一样的。但是,
读者可能已经注意到,由于这个窗格的宽度太小,因此未能将时间字符串显示完整,图 9.35只显示
了小时和分钟,没有秒数。为了把时间字符串显示完整,需要把这个窗格的宽度再加大些。这可以
利用 CStatusBar类的另一个成员函数: SetPaneInfo来实现。该函数可以为指定的窗格设置新的 B、
样式和宽度。它的原型声明如下所示:
void SetPaneInfo(int nindex, UINT nID , UINT nStyle , int cxWidth );
可以看到,这个函数有四个参数,其意义分别如下所述:
. nIndex
指定将要设置其样式的窗格索引。
.nID
为指定窗格重新设置的新 ID。
. nStyle
指示窗格的样式,表 9.6中列出了这个参数能够取的值及其意义。
表 9.6 SetPanelnfo函数的 nStyle参数取值
样式 意义
SBPS NOBORDERS 窗格周围没有 3维边框
SBPS_POPOUT 边框下陷,文本突出
SBPS DlSABLED 不绘制文本
SBPS STRETCH 伸展窗格以填充未用空间。一个控制栏只能有一个窗格具有这种样式
SBPS NORMAL 不伸展,周围有边框,但不下陷,文本也不突出
,
. cxWidth
指定窗格新的宽度。
如果想让窗格把时间文本显示完整,那么首先就要获得这个文本在显示时占据的宽度,然后直接用
这个宽度去修改窗格的宽度。根据前面的知识,我们知道这里应该调用 GetTextExtent函数来获得
时间文本的宽度。因此,对如例 9-22所示代码修改后的结果如例 9-23所示。
19IJ9-23
CTime t=CTime : :GetCurrentTime() ;
CString str=t .Format("% H:%M :% S" ) ;
CClientDC dc (this);
CSize sz=dc . GetTextExtent(str) ;
int index=. ;
index=m_wndStatusBar.CommandTolndex(IDS_TIMER) ;
m_wndStatusBar.SetPaneInfo(index , IDS_TIMER , SBPS_NORMAL , sz.cx);
m_wndStatusBar.SetPaneText (index, str) ;
Build并运行 Style程序,结果如图 9.36所示。这时,可以看到程序状态栏上将当前时间完整地显
示出来了。
图 9.36显示完整的时间字符串
但是,这个时间是一个静止的时间,我们希望能够实时地显示系统当前时间。也就是说,让这个时
间"动起来"。前面我们己经为Style程序设置了一个定时器,该定时器每隔 1秒钟发送一次WM TIMER
定时器消息,那么我们就可以在该定时器消息响应函数中再次获得系统当前时间,井设置状态栏窗
格的文本。因此,应在OnTimer函数中添加如例如24所示代码中加灰显示的代码。
19IJ 9-24
void CMainFrame: :OnTimer(UINT nIDEvent)
// TODO: Add your message handler code here and/or call default
static int index=0 ;
SetClassLong(m_hWnd, GCL_HICON, (LONG)m_hlcons[index]) ;
index=++index%3 ;
+ . CTime t=CTime::GetCurrentTime();
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) ;
CFrameWnd : :OnTimer(nIDEvent) ;
Build井运行Style,这时会看到状态栏上显示的时间实时地反映了系统当前时间,这个时间"动起来
"了。
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -