一、状态栏概述
1.1 什么是状态栏
状态栏是Windows应用程序中常见的用户界面元素,通常位于窗口底部,用于显示应用程序状态信息、提示和指示器。在MFC中,状态栏由CStatusBar类封装,它是从CControlBar派生的控件栏。
1.2 状态栏的作用
-
显示应用程序状态信息
-
提供菜单项和工具栏按钮的提示信息
-
显示系统状态(如Caps Lock、Num Lock)
-
显示进度指示
-
提供即时反馈
1.3 状态栏组件
-
窗格(Panes):状态栏被划分为多个矩形区域
-
指示器(Indicators):显示特定信息的窗格
-
提示区域(Message Line):通常是最左边的窗格,显示动态信息
二、创建状态栏
2.1 使用MFC向导自动创建
在单文档/多文档应用程序中
使用MFC应用程序向导时,可以选择"初始状态栏"选项,向导会自动生成状态栏代码:
cpp
// MainFrm.h
class CMainFrame : public CFrameWnd
{
protected:
CStatusBar m_wndStatusBar;
// ...
};
// MainFrm.cpp
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
// ... 其他代码
// 创建状态栏
if (!m_wndStatusBar.Create(this) ||
!m_wndStatusBar.SetIndicators(indicators,
sizeof(indicators)/sizeof(UINT)))
{
TRACE0("Failed to create status bar\n");
return -1; // 未能创建
}
return 0;
}
2.2 手动创建状态栏
步骤1:定义指示器数组
在MainFrm.cpp中定义指示器数组:
cpp
// 定义状态栏指示器
static UINT indicators[] =
{
ID_SEPARATOR, // 状态行指示器(消息区域)
ID_INDICATOR_CAPS, // 大写锁定指示器
ID_INDICATOR_NUM, // 数字锁定指示器
ID_INDICATOR_SCRL, // 滚动锁定指示器
};
步骤2:在OnCreate中创建
cpp
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
// 创建状态栏
if (!m_wndStatusBar.Create(this))
{
TRACE0("Failed to create status bar\n");
return -1;
}
// 设置状态栏样式
m_wndStatusBar.SetIndicators(indicators,
sizeof(indicators)/sizeof(UINT));
// 可选:设置状态栏窗格宽度
// 第一个窗格(消息区域)可伸缩,其他固定宽度
m_wndStatusBar.SetPaneInfo(0, ID_SEPARATOR, SBPS_STRETCH, 0);
m_wndStatusBar.SetPaneInfo(1, ID_INDICATOR_CAPS, SBPS_NORMAL, 40);
m_wndStatusBar.SetPaneInfo(2, ID_INDICATOR_NUM, SBPS_NORMAL, 40);
m_wndStatusBar.SetPaneInfo(3, ID_INDICATOR_SCRL, SBPS_NORMAL, 40);
return 0;
}
2.3 在对话框中创建状态栏
cpp
// 对话框类声明
class CMyDialog : public CDialog
{
protected:
CStatusBar m_wndStatusBar;
protected:
virtual BOOL OnInitDialog();
// ...
};
// 对话框初始化
BOOL CMyDialog::OnInitDialog()
{
CDialog::OnInitDialog();
// 创建状态栏
if (!m_wndStatusBar.Create(this))
{
TRACE0("Failed to create status bar\n");
return FALSE;
}
// 定义指示器
static UINT indicators[] =
{
ID_SEPARATOR,
ID_INDICATOR_CAPS,
ID_INDICATOR_NUM,
};
// 设置指示器
m_wndStatusBar.SetIndicators(indicators,
sizeof(indicators)/sizeof(UINT));
// 调整对话框大小以容纳状态栏
CRect rcClient;
GetClientRect(&rcClient);
CRect rcStatusBar;
m_wndStatusBar.GetClientRect(&rcStatusBar);
// 调整客户区
rcClient.bottom -= rcStatusBar.Height();
MoveWindow(&rcClient);
// 定位状态栏
m_wndStatusBar.SetWindowPos(NULL,
0, rcClient.Height(),
rcClient.Width(), rcStatusBar.Height(),
SWP_NOZORDER | SWP_SHOWWINDOW);
return TRUE;
}
三、状态栏样式和特性
3.1 创建样式
cpp
// 使用CreateEx创建具有特定样式的状态栏
BOOL CreateStatusBar()
{
// 创建状态栏
return m_wndStatusBar.CreateEx(this,
SBARS_SIZEGRIP, // 包含大小调整手柄
WS_CHILD | WS_VISIBLE | CBRS_BOTTOM,
ID_VIEW_STATUS_BAR);
}
// 或者使用Create函数
BOOL CreateStatusBar()
{
DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_BOTTOM;
return m_wndStatusBar.Create(this, dwStyle, ID_VIEW_STATUS_BAR);
}
3.2 状态栏样式常量
| 样式常量 | 描述 |
|---|---|
| SBARS_SIZEGRIP | 包含大小调整手柄 |
| CBRS_TOP | 停靠在顶部 |
| CBRS_BOTTOM | 停靠在底部(默认) |
| CBRS_NOALIGN | 父窗口调整大小时不重新定位 |
3.3 窗格样式常量
| 样式常量 | 描述 |
|---|---|
| SBPS_NOBORDERS | 无3D边框 |
| SBPS_POPOUT | 凸出边框 |
| SBPS_NORMAL | 正常(凹陷)边框 |
| SBPS_DISABLED | 禁用,不显示文本 |
| SBPS_STRETCH | 拉伸窗格,填满剩余空间 |
| SBPS_OWNERDRAW | 自绘窗格 |
四、状态栏操作
4.1 添加和配置窗格
cpp
// 动态添加窗格
BOOL AddPane(UINT nID, int nWidth = 100, UINT nStyle = SBPS_NORMAL)
{
// 获取当前指示器数量
int nCount = m_wndStatusBar.GetStatusBarCtrl().GetParts(0, NULL);
// 创建新的指示器数组
UINT* pIndicators = new UINT[nCount + 2]; // +1 为新窗格,+1 为终止符0
// 复制现有指示器
for (int i = 0; i < nCount; i++)
{
UINT nIDCurrent = m_wndStatusBar.GetItemID(i);
pIndicators[i] = nIDCurrent;
}
// 添加新指示器
pIndicators[nCount] = nID;
pIndicators[nCount + 1] = 0; // 终止符
// 设置新的指示器数组
BOOL bSuccess = m_wndStatusBar.SetIndicators(pIndicators, nCount + 1);
delete[] pIndicators;
if (bSuccess)
{
// 设置新窗格的宽度和样式
m_wndStatusBar.SetPaneInfo(nCount, nID, nStyle, nWidth);
}
return bSuccess;
}
// 配置现有窗格
void ConfigurePane(int nIndex, UINT nID, int nWidth, UINT nStyle)
{
m_wndStatusBar.SetPaneInfo(nIndex, nID, nStyle, nWidth);
}
// 获取窗格信息
void GetPaneInfo(int nIndex)
{
UINT nID, nStyle;
int nWidth;
m_wndStatusBar.GetPaneInfo(nIndex, nID, nStyle, nWidth);
TRACE(_T("Pane %d: ID=%d, Style=%d, Width=%d\n"),
nIndex, nID, nStyle, nWidth);
}
4.2 显示文本信息
cpp
// 在指定窗格显示文本
void ShowMessage(LPCTSTR lpszMessage, int nPane = 0, BOOL bUpdate = TRUE)
{
m_wndStatusBar.SetPaneText(nPane, lpszMessage);
if (bUpdate)
{
m_wndStatusBar.UpdateWindow();
}
}
// 格式化文本显示
void ShowFormattedMessage(int nPane, LPCTSTR lpszFormat, ...)
{
CString strMessage;
va_list args;
va_start(args, lpszFormat);
strMessage.FormatV(lpszFormat, args);
va_end(args);
m_wndStatusBar.SetPaneText(nPane, strMessage);
}
// 获取窗格文本
CString GetPaneText(int nPane)
{
CString strText;
m_wndStatusBar.GetPaneText(nPane, strText);
return strText;
}
// 临时消息显示(定时消失)
void ShowTemporaryMessage(LPCTSTR lpszMessage, int nTimeout = 3000)
{
// 保存当前消息
static CString s_strSavedMessage;
static int s_nSavedPane = 0;
s_nSavedPane = 0; // 假设使用第一个窗格
m_wndStatusBar.GetPaneText(s_nSavedPane, s_strSavedMessage);
// 显示新消息
m_wndStatusBar.SetPaneText(s_nSavedPane, lpszMessage);
// 设置定时器恢复原消息
SetTimer(ID_TIMER_RESTORE_MESSAGE, nTimeout, NULL);
}
// 处理定时器消息恢复原消息
void CMainFrame::OnTimer(UINT_PTR nIDEvent)
{
if (nIDEvent == ID_TIMER_RESTORE_MESSAGE)
{
KillTimer(ID_TIMER_RESTORE_MESSAGE);
m_wndStatusBar.SetPaneText(0, s_strSavedMessage);
}
CFrameWnd::OnTimer(nIDEvent);
}
4.3 启用/禁用窗格
cpp
// 启用或禁用窗格
void EnablePane(int nIndex, BOOL bEnable)
{
UINT nID, nStyle;
int nWidth;
m_wndStatusBar.GetPaneInfo(nIndex, nID, nStyle, nWidth);
if (bEnable)
{
nStyle &= ~SBPS_DISABLED;
}
else
{
nStyle |= SBPS_DISABLED;
}
m_wndStatusBar.SetPaneInfo(nIndex, nID, nStyle, nWidth);
}
// 显示/隐藏窗格
void ShowPane(int nIndex, BOOL bShow)
{
// 通过设置宽度为0来隐藏窗格
UINT nID, nStyle;
int nWidth;
m_wndStatusBar.GetPaneInfo(nIndex, nID, nStyle, nWidth);
if (bShow)
{
// 恢复原始宽度(需要提前保存)
static std::map<int, int> s_mapPaneWidths;
if (s_mapPaneWidths.find(nIndex) != s_mapPaneWidths.end())
{
nWidth = s_mapPaneWidths[nIndex];
}
else
{
nWidth = 100; // 默认宽度
}
}
else
{
// 保存宽度并设置为0
static std::map<int, int> s_mapPaneWidths;
s_mapPaneWidths[nIndex] = nWidth;
nWidth = 0;
}
m_wndStatusBar.SetPaneInfo(nIndex, nID, nStyle, nWidth);
m_wndStatusBar.Invalidate();
}