状态栏

Posted Autumn の Box

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了状态栏相关的知识,希望对你有一定的参考价值。

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);
}

 

以上是关于状态栏的主要内容,如果未能解决你的问题,请参考以下文章

在底部导航栏中保存片段状态

保存片段状态操作栏选项卡

在片段中使用 CoordinatorLayout 时如何使状态栏透明

Android 全屏片段不显示导航和状态栏后面的元素

带有透明状态栏的全屏片段(以编程方式)

状态栏在全屏对话框片段android中将其颜色更改为黑色