1、相关类
CStatusBar -父类CControlBar,封装了关于状态栏的操作,也包括状态栏的创建
2、状态栏的使用
2.1创建状态栏 CStatusBar::CreateEx / CStatusBar::Create
BOOL CreateEx(
CWnd* pParentWnd, //指定状态栏的父窗口指针,通常都是指向程序的框架类窗口对象
DWORD dwCtrlStyle = 0 , //设置内嵌在状态栏上的CStatusBarCtrl对象创建时的扩展风格
DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_BOTTOM, //状态栏的风格
UINT nID = AFX_IDW_STATUS_BAR //指定状态栏这个子窗口的ID,默认为AFX_IDW_STATUS_BAR
);
BOOL Create(
CWnd* pParentWnd, //指定状态栏的父窗口指针,通常都是指向程序的框架类窗口对象
DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_BOTTOM, //状态栏的风格
UINT nID = AFX_IDW_STATUS_BAR //指定状态栏这个子窗口的ID,默认为AFX_IDW_STATUS_BAR
);
在程序的CMainFrame类的OnCreate函数中可见MFC自动创建状态栏的方法:
if (!m_wndStatusBar.Create(this) || !m_wndStatusBar.SetIndicators( indicators,sizeof(indicators)/sizeof(UINT))) { TRACE0("Failed to create status bar\n"); return -1; // fail to create }
SetIndicators函数的第一个参数indicators为一个静态数组,其定义在CMainFrame类的源文件中:
static UINT indicators[] =
{
ID_SEPARATOR, //提示行
ID_INDICATOR_CAPS, //Caps Lock键的状态指示器
ID_INDICATOR_NUM, //Num Lock键的状态指示器
ID_INDICATOR_SCRL, //Scroll Lock键的状态指示器
};
该数组中的后3个ID都是MFC预先定义好的字符串资源ID,在工程的资源窗口中的String Table的字串表中可见:
若要修改状态栏的外观,如添加或减少状态栏上的窗格,只需要在indicators数组中添加或减少相应的字符串资源ID即可;
2.2设置状态栏指示器(窗格)
CStatusBar::SetIndicators
2.3设置指示器(窗格)的宽度和风格
CStatusBar::SetPaneInfo
void SetPaneInfo(
int nIndex, //指定要设置其样式的窗格的位置索引
UINT nID, //为指定窗格重新设置的新ID
UINT nStyle, //窗格的样式:SBPS_NORMAL/SBPS_STRETCH/SBPS_DISABLED/SBPS_POPOUT/SBPS_NOBORDERS
int cxWidth //指定窗格的宽度
);
2.4设置指示器(窗格)的文本内容
CStatusBar::SetPaneText
BOOL SetPaneText(
int nIndex, //当前窗格在指示器数组(indicators)中的位置索引
LPCTSTR lpszNewText, //要在当前窗格中显示的文本
BOOL bUpdate = TRUE
);
若不知道当前窗格在指示器数组(indicators)中的位置索引,可利用CStatusBar::CommandToIndex
int CommandToIndex( UINT nIDFind ); //根据指定的资源ID获得相应的位置索引
本例将在状态栏上显示当前系统的时间和一个进度条控件:
1、显示系统时间
在程序资源窗口中的字串表中增加两个新的字符串资源:
将这两个新的字符串资源ID添加到CMainFrame类的源文件中的indicators数组中:
static UINT indicators[] = { ID_SEPARATOR, IDS_TIMER, IDS_PROGRESS, ID_INDICATOR_CAPS, ID_INDICATOR_NUM, ID_INDICATOR_SCRL, };
利用CTime类的静态成员函数GetCurrentTime获取系统当前的时间对象;再调用CTime类的另一个成员函数Format对得到的时间对象进行格式化,得到一个包含格式化时间的字符串;调用SetPaneInfo函数修改窗格的显示宽度以装下将要显示的字符串文本;调用SetPaneText函数将该字符串显示到状态栏的窗格中;
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { ...... CTime t=CTime::GetCurrentTime(); CString str=t.Format("%Y-%m-%d %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); return 0; }
此时在状态栏窗格中显示的时间是静止的,利用定时器每隔一秒就发送WM_TIMER消息,在消息响应函数OnTimer中重新获取一次系统当前时间并显示到状态栏窗格中,已达到显示动态时间的效果;
在CMainFrame类的OnCreate函数中埋下定时器:
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { ...... SetTimer(1,1000,NULL); return 0; }
为CMainFrame类添加WM_TIMER消息,生成消息响应函数OnTimer,在该函数中重新执行一次系统时间的获取并显示到状态栏窗格中:
void CMainFrame::OnTimer(UINT nIDEvent) { // TODO: Add your message handler code here and/or call default CTime t=CTime::GetCurrentTime(); CString str=t.Format("%Y-%m-%d %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); }
2、进度条控件
要在程序中使用进度栏,首先需要构造一个CProgressCtrl对象,然后调用CProgressCtrl类的Create函数创建进度栏控件;
BOOL Create(
DWORD dwStyle, //进度栏控件的类型,窗口所有的类型+PBS_VERTICAL(进度栏垂直)/PBS_SMOOTH(进度栏连续)
const RECT& rect, //进度栏控件的大小、位置
CWnd* pParentWnd, //进度栏的父窗口
UINT nID //指定进度栏控件的ID
);
在程序的CMainFrame类中添加成员变量:CProgressCtrl m_progress
要在状态栏的窗格中显示进度栏,首先利用GetItemRect函数获得该窗格的区域大小:
void GetItemRect(int nIndex, LPRECT lpRect ) const;
nIndex:指定窗格的位置索引
lpRect:窗格的矩形区域
当程序窗口第一次显示时就会发送WM_PAINT消息,而且当程序的窗口尺寸发生变化需要重绘时也会发送WM_PAINT消息,故可在WM_PAINT消息的响应函数中判断,若程序还未创建进度栏则创建它,若已创建则将进度栏移动至目标窗格的矩形区域中;
为CMainFrame类添加WM_PAINT消息的响应函数:
void CMainFrame::OnPaint() { CPaintDC dc(this); // device context for painting // TODO: Add your message handler code here CRect rect; m_wndStatusBar.GetItemRect(2,&rect); //获得状态栏中窗格的矩形区域 if(!m_progress.m_hWnd){ //判断当m_progress对象的句柄为NULL时,说明该对象还未创建,则创建进度栏 m_progress.Create(WS_CHILD|WS_VISIBLE,rect,&m_wndStatusBar,123); //创建进度栏 }else{ m_progress.MoveWindow(rect); //将进度栏移至目标矩形中 } m_progress.SetPos(50); //设置进度栏的当前进度 // Do not call CFrameWnd::OnPaint() for painting messages }
若要实现进度栏进度的动态增加,需要利用定时器,在WM_TIMER消息的响应函数OnTimer函数中实现:
void CMainFrame::OnTimer(UINT nIDEvent) { ...... m_progress.StepIt(); CFrameWnd::OnTimer(nIDEvent); }
CProgressCtrl::StepIt:使进度栏控件的进度按照一定的步长增加
CProgressCtrl::SetStep:设置进度栏每次增加的步长
CProgressCtrl::SetRange:设置进度栏的范围,默认为0~100
3、在状态栏上显示鼠标当前的位置
当在程序的客户区窗口移动鼠标时,将鼠标当前的坐标位置显示在状态栏的提示行上;
首先需要在程序的CStyleView类中添加WM_MOUSEMOVE消息的响应函数:
因为GetParent函数返回的为CWnd类型的指针,需要强制转换为CMainFrame类型的指针,故须在视图类的源文件中包含框架类的头文件:
#include "MainFrm.h"
在WM_MOUSEMOVE消息的响应函数中,实现状态栏对象的获取及在其窗格中的文本显示:
void CStyleView::OnMouseMove(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default CString str; str.Format("x=%d,y=%d",point.x,point.y); //格式化鼠标坐标位置的信息 //通过调用GetParent函数获取视图类的父窗口即框架类窗口,将返回值强制转换后,调用框架窗口对象中的状态栏成员变量 ((CMainFrame*)GetParent())->m_wndStatusBar.SetWindowText(str); CView::OnMouseMove(nFlags, point); }
将鼠标当前位置信息显示到状态栏对象的提示行中的方法:
方法一:SetWindowText
框架类CMainFrame类的状态栏成员变量m_wndStatusBar默认在CMainFrame类的头文件中被定义为protected类型,须手动将其修改为public类型才能被调用;
方法二:CFrameWnd类的成员函数:SetMessageText
该函数的作用即为在ID为0的状态栏窗格(即提示行)设置一个字符串;因程序框架类CMainFrame类派生于CFrameWnd类,故这里可以直接用框架类对象调用该成员函数来设置状态栏文本;
void CStyleView::OnMouseMove(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default CString str; str.Format("x=%d,y=%d",point.x,point.y); //((CMainFrame*)GetParent())->m_wndStatusBar.SetWindowText(str); ((CMainFrame*)GetParent())->SetMessageText(str); CView::OnMouseMove(nFlags, point); }
方法三:CFrameWnd类的成员函数:GetMessageBar
该函数返回状态栏对象的指针,故无须像方法一那样修改并调用CMainFrame类的保护成员变量m_wndStatusBar了,可直接调用SetWindowText函数设置状态栏的第一个窗格(提示行)的文本;
void CStyleView::OnMouseMove(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default CString str; str.Format("x=%d,y=%d",point.x,point.y); //((CMainFrame*)GetParent())->m_wndStatusBar.SetWindowText(str); //((CMainFrame*)GetParent())->SetMessageText(str); ((CMainFrame*)GetParent())->GetMessageBar()->SetWindowText(str); CView::OnMouseMove(nFlags, point); }
方法四:CWnd类的成员函数:GetDescendantWindow
该函数可通过指定的ID来获得当前窗口的所有子孙窗口,因状态栏属于框架类窗口,故先要得到框架类窗口的指针,然后根据状态栏的窗口ID调用该函数获得状态栏对象的指针
void CStyleView::OnMouseMove(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default CString str; str.Format("x=%d,y=%d",point.x,point.y); //((CMainFrame*)GetParent())->m_wndStatusBar.SetWindowText(str); //((CMainFrame*)GetParent())->SetMessageText(str); //((CMainFrame*)GetParent())->GetMessageBar()->SetWindowText(str); GetParent()->GetDescendantWindow(AFX_IDW_STATUS_BAR)->SetWindowText(str); CView::OnMouseMove(nFlags, point); }