|
4.3 状态栏的设计与实现 状态栏实际上是个窗口,一般分为几个窗格,每个窗格显示不同的信息。AppWizard会为应用程序自动创建一个状态栏,该状态栏包括几个窗格,分别用来显示状态栏提示和CAPS LOCK、NUM LOCK 、SCROLL LOCK键的状态。在MFC中,状态栏的功能由CStatusBar类实现。 创建一个状态栏需要以下几个步骤:
相应的代码读者可以在Record工程的CMainFrame::OnCreate成员函数中找到。如清单4.6所示。 清单4.6 创建状态栏 … 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是一个ID数组,在CMainFrame类所在的CPP文件的开头部分可以找到该数组,如清单4.7所示。 清单4.7 ID数组 static UINT indicators[] = { ID_SEPARATOR, // status line indicator ID_INDICATOR_CAPS, ID_INDICATOR_NUM, ID_INDICATOR_SCRL, }; indicator数组提供了状态栏窗格的分配信息,它的第一项一般为ID_SEPARATOR,该ID对应的窗格用来显示命令提示信息,后三项都是字符串ID,读者可以在String Table字符串资源中找到这三个字符串分别是CAP、NUM和SCRL。它们对应的三个窗格用来显示键盘的状态。 现在让我们来给状态栏再加一个时间窗格,它将用来显示系统时间。显示的格式是hh:mm:ss,即时:分:秒。 首先在indicators数组的ID_SEPARATOR项之后插入一个名为ID_INDICATOR_CLOCK的ID。然后找到并双击名为String Table的字符串资源,打开字符串资源编辑窗口。接着在编辑窗口内按Insert键以插入一个新的字符串,请指定字符串的ID为ID_INDICATOR_CLOCK,内容为00:00:00。状态栏将根据字符串的长度来确定相应窗格的缺省宽度,所以指定为00:00:00就为时间的显示预留了空间。
时间窗格显示的时间必须每隔一秒钟更新一次。更新时间窗格的正文可调用CStatusBar:: SetPaneText函数,要定时更新,则应利用WM_TIMER消息。在Windows中用户可以安装一个或多个计时器,计时器每隔一定的时间间隔就会自动发出一个WM_TIMER消息,而这个时间间隔可由用户指定。MFC的Window类提供了WM_TIMER消息处理函数OnTimer,我们应在该函数内进行更新时间窗格的工作。 请读者利用ClassWizard给CMainFrame类加入WM_TIMER的消息处理函数OnTimer和WM_CLOSE消息的处理函数OnClose,具体方法是在Class name栏中选择CMainFrame,在Object IDs栏中选择CMainFrame,在Messages栏中找到WM_TIMER和WM_CLOSE项,分别双击之然后按OK按钮退出ClassWizard。CMainFrame::OnClose函数是在关闭主框架窗口是被调用的,程序可以在该函数中做一些清除工作。 接下来请按清单4.8修改程序。 清单4.8 CMainFrame类的部分代码 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { … SetTimer(1,1000,NULL); return 0; } void CMainFrame::OnTimer(UINT nIDEvent) { // TODO: Add your message handler code here and/or call default
CTime time; time=CTime::GetCurrentTime(); CString s=time.Format("%H:%M:%S");
CFrameWnd::OnTimer(nIDEvent); } void CMainFrame::OnClose() { // TODO: Add your message handler code here and/or call default
KillTimer(1); CFrameWnd::OnClose(); } 在CMainFrame::OnCreate函数内调用了CWnd::SetTimer以安装一个计时器,SetTimer的第一个参数指定计时器ID为1,第二个参数则规定了计时器的时间间隔为1000毫秒即1秒。这样,每隔1秒OnTimer函数就会被调用一次。 在OnTimer函数中,首先构建了一个CTime对象,接着调用CTime的静态成员函数GetCurrentTime以获得当前的系统时间,然后利用CTime::Format函数返回一个按时:分:秒的格式表示的字符串,最后调用CStatusBar::SetPaneText来更新时间窗格显示的正文。SetPaneText的第一个参数是窗格的索引,对于某一个窗格ID,可调用CStatusBar::CommandToIndex来获得索引。 在撤销主框架窗口时应关闭计时器,因此在CMainFrame::OnClose函数内调用了KillTimer函数。 现在让我们来看一下CMainFrame的消息映射,在CMainFrame类所在CPP文件的开始部分可以找到该类的消息映射,如清单4.9所示。 清单4.9 BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) //{{AFX_MSG_MAP(CMainFrame) ON_WM_CREATE() ON_COMMAND(ID_RECORD_STOP, OnRecordStop) ON_COMMAND(ID_RECORD_START, OnRecordStart) ON_UPDATE_COMMAND_UI(ID_RECORD_START, OnUpdateRecordStart) ON_UPDATE_COMMAND_UI(ID_RECORD_STOP, OnUpdateRecordStop) ON_COMMAND(ID_HIGH_QUALITY, OnHighQuality) ON_COMMAND(ID_LOW_QUALITY, OnLowQuality) ON_UPDATE_COMMAND_UI(ID_HIGH_QUALITY, OnUpdateHighQuality) ON_UPDATE_COMMAND_UI(ID_LOW_QUALITY, OnUpdateLowQuality) ON_COMMAND(ID_VIEW_TOOLBAR1, OnViewToolbar1) ON_UPDATE_COMMAND_UI(ID_VIEW_TOOLBAR1, OnUpdateViewToolbar1) ON_WM_TIMER() ON_WM_CLOSE() //}}AFX_MSG_MAP END_MESSAGE_MAP() 读者可以看到,在消息映射表中,ClassWizard为消息处理函数和命令处理函数自动加入了消息映射。自动加入的部分呈灰色显示,位于注释行//{{AFX_MSG_MAP和//}}AFX_MSG_MAP 之间。命令处理函数由ON_COMMAND宏来映射,命令更新处理函数由ON_UPDATE_COMMAND_UI,而WM_消息的处理函数由ON_WM_消息宏来映射。
编译并运行Record ,可以看到状态栏的新变化,最终的界面如图4.8所示。
图4.8 最终的Record程序 小 结
作者: 不详, 来源: Visual C++王朝 |