1.36k likes | 1.47k Views
第四章 装饰应用程序的外观. 创建友好 , 美观的 用户界面 是成功设计和编制一个 Windows 应 用程序的重要组成部分,程序 用户界面 的设计编程工作包括 菜单 、 控制栏 ( 其中包括 工具栏 、 状态栏 、 对话框栏 等) 创建和控制、 对话框 、 帮助信息 的制作和运行,以及 框架 、 视图窗口 的位置和大小控制等。其中对话框的制作和运行操作将在下一 章中作详细的描述。 在 AppWizard 创建的应用程序框架中, 菜单 , 工具栏 , 状态栏 和 视图窗口 均可以缺省隶属于 主框架窗口 ,并由 主框架窗口 管
E N D
创建友好, 美观的用户界面是成功设计和编制一个 Windows 应 用程序的重要组成部分,程序用户界面的设计编程工作包括菜单、控制栏( 其中包括工具栏、状态栏、对话框栏等) 创建和控制、对话框、帮助信息的制作和运行,以及框架、视图窗口的位置和大小控制等。其中对话框的制作和运行操作将在下一 章中作详细的描述。 在 AppWizard创建的应用程序框架中,菜单,工具栏, 状态栏 和视图窗口均可以缺省隶属于主框架窗口,并由主框架窗口管 理和控制。一个典型主框架窗口的组成以及与用户界面各个组 成部分的关系如下图所示:
SDI主框架窗口 子窗口 ⑴SDI应用程序框架 标题栏 菜单栏 工具栏窗口 视图窗口 状态栏窗口
MDI主框架窗口 MDI子框架窗口 子窗口 ⑵MDI应用程序框架 标题栏 菜单栏 工具栏窗口 标题栏 视图窗口 状态栏窗口
MFC AppWizard 所生成的应用程序主框架窗口可以选择拥有缺 省的基本菜单、相应的工具栏、状态栏和由系统自动确定框架 窗口位置和尺寸,但在实际编程中往往需要在此基础上修改和 添加自定义的菜单、工具栏、状态栏以及由用户确定框架窗口 位置和尺寸,使应用程序外观满足特定的程序功能、特定的用 户和特定的使用环境的需要。 MFC 为工具栏,状态栏,菜单,主框架窗口提供了相应的基类,以便实现对这些程序外观组成部分的创建和各种操作。这些类在 MFC 中的派生层次结构如下:
CCmdTarget CWnd CControlBar CToolBar CStatusBar CDialogBar CReBar ·工具栏和状态栏分别由 CToolBar和 CStatusBar 类描述, 它们都是控制栏类 CControlBar的派生类,而 CControlBar又是 CWnd 的派生类,因此,工具栏和状态栏本身也是一个能响 应消息的特定窗口,在主框架窗口中可以视为是子窗口。 CObject
CMenu ·菜单是由 CMenu类描述, 它是直接从 CObject类派生的,因此该类的对象只能用于完 成菜单的创建、跟踪、修改、销毁和发送命令消息,而本身 不能响应消息;在主框架窗中可以视为用于发送命令消息的 一个特定区域。 CObject
CCmdTarget CWnd CFrameWnd CMDIFrameWnd CMDIChildWnd ·主框架窗口是由 CFrameWnd(用于 SDI)或 CMDIFrameWnd 和 CMDIChildWnd(用于 MDI),它们都是 CWnd的直接或间接派 生类。 CObject
由 AppWizard创建的文档视图结构的应用程序主框架窗口类 对象中缺省的工具栏被定义成名为 m_wndToolBar 的 CToolBar类 对象成员,而状态栏被定义成名为 m_wndStatusBar 的CStatusBar 类对象成员。创建和显示工具栏和状态栏的操作应在程序主框 架窗类 CMainFrame 对象所关联的窗口已经创建完成(窗口句柄已有效) 但还未显示时进行,即在窗口创建消息 WM_CREATE 的响应成员函数 OnCreate被调用中完成的。因此,需要在 CMainFrame类中重新定义 OnCreate 函数,以便在主框架窗口显 示之前添加任何需要附加的初始化工作,例如创建和显示工具 栏和状态栏、创建其他子窗口等。
与其它 Windows资源所对应的 MFC类一样,CMenu类也是将菜 单的句柄和属性和对菜单属性的各种操作等封装了起来,并且 只有当菜单句柄有效时,对菜单属性的操作才是合法的。通常 情况下,菜单总是主框架窗口的一个区域,所以当主框架窗口 的产生函数或 LoadFrame函数被调用时,与菜单资源相关联的 CMenu对象作为框架窗口的保护成员被创建。 因此,通常情况下,编程者只需要通过设计菜单的静态资 源,而且无须通过 CMenu类对象的调用对象的行为,就能满足 程序对主菜单的一般设计编程需求。但在程序需要动态创建新 菜单或修改已有菜单时,则必须调用 CMenu对象的行为。
如果你需要修改主框架窗口的菜单,你可能需要通过窗口类 CWnd的成员函数 GetMenu获取保护成员 CMenu对象的指针, 并通过该指针对该菜单对象进行各种需要的访问和操作,以便 满足特殊的菜单设计编程需求,例如: ·动态切换不同菜单; ·动态隐藏和显示菜单; ·动态添加和删除菜单项; ·动态禁止和激活菜单项; ·动态为菜单项添加图形标签; ·动态创建浮动的弹出式环境菜单。
对框架和视图窗口的外观操作,就是对它们的位置、大小、状对框架和视图窗口的外观操作,就是对它们的位置、大小、状 态的控制,称之为放置(Placement)操作。视图窗口是包含在 框架窗口中的,它随着框架窗口的变化而变化,换句话说,对 视图窗口的放置操作是通过对框架窗口的放置操作实现的。虽 然用户可以方便地通过框架窗口提供的最大化、最小化等窗口 操作界面对框架和视图窗口的放置进行动态交互控制,但在不 少情况下,还是需要在程序中通过代码对框架和视图窗口的放 置进行定制操作。例如,希望程序在运行开始时能保持最近一 次运行的框架和视图窗口的位置、大小、状态。实现这些放置 操作是窗口创建过程中完成的,这对于 SDI和 MDI应用程序是 不完全一样的,对于 MDI,不仅要考虑主框架窗口的放置,还 要考虑子框架窗口的放置。
本章将通过 5类实例程序分别讲述如何实现上述外观设计: ·第 1类实例讲解工具栏和状态栏编程; ·第 2类实例讲解 CDialogBar编程; ·第 3类实例讲解 CReBar编程; ·第 4类实例讲解菜单编程; ·第 5类实例讲解具有持续特性的定制框架窗口类编程。
4.1 创建浮动工具栏 4.1.1 利用 AppWizard自动创建工具栏 在 MFC中,工具栏资源和工具栏类 CToolBar是实现工具栏的 两个要素。创建工具栏对象的基本步骤为: ·创建工具栏资源; ·创建一个 CToolBar对象; ·调用 CToolBar::Create函数创建工具栏窗口; ·调用 CToolBar::LoadToolBar载入工具栏资源。
在使用 AppWizard生成的默认配置的应用程序框架中包括了 能创建一个缺省工具栏的四步操作的所有代码,因此修改工具 栏中的按钮只需要修改缺省工具栏资源就可以实现。而如果需 要创建缺省工具栏以外的工具栏,则必须在 AppWizard生成的框 架基础上,效仿上述缺省资源和代码添加相应的自定义资源和 代码。为此,分析创建缺省工具栏的代码是十分必要的。 创建一个 SDI 应用程序项目 “Default” (使用 AppWizard 的缺 省选择),查询所创建的应用程序框架的代码,可以发现与工 具栏有关的资源和代码有:
1 在资源中添加了工具栏资源 IDR_MAINFRAME: 2 在 CMainWnd的定义中添加了定义工具栏对象成员的代码: CToolBar m_wndToolBar; 3 在重新定义的 CMainWnd::OnCreate中添加了创建工具栏, 装 载工具资源和初始化工具栏的缺省代码。 分析 CMainWnd::OnCreate,该虚函数首先调用了基类中定义 的版本 CFrameWnd::OnCreate进行基类部分的初始化工作, 然后可以添加主框架窗口所需要的任何初始化代码,其中包 括了对工具栏的创建和初始化操作:
⑴创建工具栏窗口 创建工具栏窗口的函数是 CToolBar::Create 或CToolBar::CreateEx 它们的原型分别为: BOOL Create( CWnd *pParentWnd, // 父窗口指针 DWORD dwStyle = WS_CHILD| WS_VISIBLE|CBRS_TOP, // 风格 UINT nID=AFX_IDW_TOOLBAR /* 工具栏子窗口 ID */ ); BOOL CreateEx(CWnd* pParentWnd, //父窗口指针 DWORD dwCtrlStyle = TBSTYLE_FLAT, // 工具栏控件风格 DWORD dwStyle = WS_CHILD| WS_VISIBLE|CBRS_ALIGN_TOP, CRect rcBorders=CRect(0,0,0,0),// 工具栏的矩形边界 UINT nID=AFX_IDW_TOOLBAR /* 工具栏子窗口 ID */ );
其中: ·pParentWnd是指向工具栏的父窗口,即主框架窗口对象的 指针。 ·dwCtrlStyle和 dwStyle的设置是决定所创建的工具栏的外观 和状态的重要因素,可设置的样式值包括 CWnd的样式和 CToolBar 的样式两部分(祥见 MSDN的有关部分)。 ·如果创建成功,返回真实的;否则返回错误的。 例如,在本例中实现创建工具栏窗口的缺省代码为: m_wndToolBar.CreateEx( this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE| CBRS_TOP|CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY|CBRS_SIZE_DYNAMIC ); 注意,该调用中第 4参数 rcBorders和第 5参数 nID使用了缺省 值 CRect(0,0,0,0)和AFX_IDW_TOOLBAR 。
⑵加载工具栏资源 为工具栏对象加载资源的函数为 CToolBar::LoadToolBar,其 原型为: BOOL LoadToolBar ( LPCTSTR lpszResourceName /*资源名 */ ); BOOL LoadToolBar ( UINT nIDResource /* 资源 ID */ ); 本例中实现加载工具栏资源的代码为: m_wndToolBar.LoadToolBar ( IDR_MAINFRAME ); IDR_MAINFRAME 是工具栏资源的 ID。如果资源加载成功,则 返回 TRUE的;否则返回 FALSE的。
⑶设置工具栏停靠特性 实现设置的函数为 CControlBar::EnableDocking,其原型为: void EnableDocking ( DWORD dwStyle ); 参数为停靠样式,种类和取值参考 MSDN中的相关部分。 本例中实现设置的代码为: m_wndToolBar.EnableDocking ( CBRS_ALIGN_ANY ); 参数 CBRS_ALIGN_ANY 所指示的停靠样式是允许工具栏停靠 到主框架窗口中的任何一边。
⑷设置主框架窗口的工具栏停靠特性 实现该设置的函数为 CFrameWnd::EnableDocking,其原型: void EnableDocking ( DWORD dwdocStyle ); 参数为停靠样式,种类和取值参考 MSDN中的相关部分。 本例中实现设置的代码为: EnableDocking ( CBRS_ALIGN_ANY ); 参数 CBRS_ALIGN_ANY 所指示的停靠样式是使框架窗口的任 何一边都可以停放控制栏。在拥有多个控制栏的框架窗口中 该函数只需调用一次。
⑸把工具栏停靠在主框架窗口中的确定位置 实现停靠操作的函数为 CFrameWnd::DockControlBar,原型: void DockControlBar ( CControlBar*pBar, UINT nDockBarID=0, LPCRECT lpRect=NULL ); 本例中实现停靠的代码为: DockControlBar (&m_wndToolBar); 使工具栏按照创建工具栏窗口时的默认位置(框架窗口工作 区的顶部),实现停靠操作。
4.1.2 添加自定义工具栏 创建一个名为 "Tb" 的 SDI应用程序项目,参照由 AppWizard 缺省创建的工具栏添加自定义工具栏。 1 自定义工具栏资源 使用资源编辑器添加一个标识为 ID_TOOLBAR1的工具栏资源 其中包括两个按钮: 2. 添加自定义工具栏的程序代码 ⑴ 在 CMainFrame类中增加一个 CToolBar类的保护成员对象: CToolBar m_wndToolBar1; ⑵ 在 CMainFrame::OnCreate添加对应于 m_wndToolBar1的创建、 加载资源和初始化代码:
… if ( !m_wndToolBar1.CreateEx ( this,TBSTYLE_FLAT,WS_CHILD | WS_VISIBLE | CBRS_TOP|CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) || !m_wndToolBar1.LoadToolBar ( IDR_TOOLBAR1 ) ) { TRACE0 (" Failed to create toolbar\n "); return -1; // fail to create } … m_wndToolBar1.EnableDocking (CBRS_ALIGN_ANY); … DockControlBar (&m_wndToolBar1); 此时编译运行应用程序,可以看到新增加的自定义工具栏, 但工具栏中的按钮是灰色的,即不能对它进行任何操作。
4.1.3 自定义工具栏的命令响应及其用户界面更新 在 CTbView 类中,添加工具栏按钮 ID_LINE和 ID_CIRCLE的 命令消息和界面更新命令消息的响应。 1 为 CTbView类增加保护数据成员和枚举: int m_nDraw; // 指示当前的绘图类别。 enum{LINE,CIRCLE}; // 定义可以使用的绘图类别。 2 在 CTbView的构造函数中对 m_nDraw进行初始化: m_nDraw = LINE; 3. 使用 ClassWizard为命令消息 ID_LINE和 ID_CIRCLE定义命令 响应函数和用户界面更新函数。 在类定义文件中添加了这些成员函数的原型:
afx_msg void OnLine (); afx_msg void OnCircle (); afx_msg void OnUpdateLine (CCmdUI*pCmdUI); afx_msg void OnUpdateCircle (CCmdUI*pCmdUI); 在类实现文件中添加了上述成员函数的操作定义如下: void CTbView::OnLine() { m_nDraw = LINE; }
void CTbView::OnCircle() { m_nDraw = CIRCLE; } void CTbView::OnUpdateLine (CCmdUI*pCmdUI) { pCmdUI->SetCheck(m_nDraw == LINE); } void CTbView::OnUpdateCircle(CCmdUI*pCmdUI) { pCmdUI->SetCheck(m_nDraw == CIRCLE); } 4 编译运行 "Tb"
4.1.4 自定义工具栏的隐藏/显示 要使自定义的工具栏能像缺省工具栏那样具有隐藏和显示操 作功能必须添加以下资源和代码: 1 在主菜单 IDR_MAINFRAME的“查看”弹出菜单中增加新的菜单 项 "自定义工具栏" ,其标识值为 ID_VIEW_TOOLBAR1 2 在主框架窗口类 CMainFrame 中,为 ID_VIEW_TOOLBAR1定义 命令响应函数和用户界面更新函数 在类定义文件中添加这些成员函数的原型: afx_msg voidOnViewToolbar1(); afx_msg voidOnUpdateViewToolbar1( CCmdUI* pCmdUI );
在类实现文件中添加上述成员函数的操作定义:在类实现文件中添加上述成员函数的操作定义: void CMainFrame::OnViewToolbar1() { ShowControlBar( &m_wndToolBar1, m_wndToolBar1.IsWindowVisible() ? FALSE : TRUE, FALSE ); } void CMainFrame::OnUpdateViewToolbar1( CCmdUI* pCmdUI ) { pCmdUI->SetCheck( m_wndToolBar1.IsWindowVisible( ) ); } 3 编译运行"Tb"
4.1.5 动态删除和添加工具栏中按钮 如果希望通过程序动态地从已经创建的工具栏中删除一些按 钮或向工具栏中添加一些按钮,则需要使用CToolBar类对象中 的 CToolBarCtrl类对象成员来实现,而这个对象成员可以通过 调用 CToolBar::GetToolBarCtrl函数获得实例 "Tb1" 是在实例 "Tb" 的基础上增加了通过程序代码对工具栏中的按钮进行动态删除 和添加的功能: 1 在 CMainFrame类定义中增加下列保护数据成员: // for saving buttons of the m_wndToolBar TBBUTTON m_tbButtons[11]; // for saving the most and least count of buttons int m_nMost, m_nLeast;
2 在 CMainFrame::OnCreate中增加下列初始化代码: // Save some TBBUTTONs for restoring later m_nMost = m_wndToolBar.GetToolBarCtrl().GetButtonCount(); // Save the most count of buttons for(int I = 2; I < m_nMost - 1; i++) m_wndToolBar.GetToolBarCtrl().GetButton(i, &m_tbButtons[i]); // Delete some buttons from m_wndToolBar. DeleteTBButtons(2,m_nMost - 3); // Save the least count of buttons m_nLeast = m_wndToolBar.GetToolBarCtrl().GetButtonCount();
3 为 CMainFrame定义删除和恢复工具栏按钮的保护成员函数: 在定义文件中增加这两个函数的原型声明: void RecoverTBButtons ( int index,int count ); void DeleteTBButtons ( int index, int count ); 在实现文件中增加这两个函数的定义代码: void CMainFrame::DeleteTBButtons( int index,int count) { for ( int I = index; I < index + count; i++) m_wndToolBar.GetToolBarCtrl().DeleteButton(index); //从工具栏中顺序删除索引为 index 的按钮。 ShowControlBar(&m_wndToolBar,TRUE, TRUE); //重新显示变化后的工具栏。 }
void CMainFrame::RecoverTBButtons(int index, int count) { for (int I = index; I < index + count; i++) // 将删除的按钮顺序恢复插入到工具栏中。 m_wndToolBar.GetToolBarCtrl().InsertButton(i, &m_tbButtons[i]); //重新显示变化后的工具栏。 ShowControlBar(&m_wndToolBar, TRUE, TRUE); } 4 在主菜单资源 IDR_MAINFRAME的“查看”菜单中增加菜单项: “删除工具栏中的按钮”和“恢复工具栏中的按钮”,它们的标识 为:ID_DELETE_BUTTONS和 ID_RECOVER_BUTTONS。
5 使用 ClassWizard 在 CMainFrame类中为 ID_DELETE_BUTTONS 和 ID_INSERT_BUTTONS 添加命令消息响应和用户界面更新函数。 在类定义文件中增加了: afx_msg void OnDeleteButtons (); afx_msg void OnRecoverButtons (); afx_msg void OnUpdateDeleteButtons (CCmdUI* pCmdUI); afx_msg void OnUpdateRecoverButtons (CCmdUI* pCmdUI); 在类实现文件中增加了命令映射项和消息响应函数: ON_COMMAND(ID_DELETE_BUTTONS, OnDeleteButtons) ON_COMMAND(ID_INSERT_BUTTONS, OnRecoverButtons)
ON_UPDATE_COMMAND_UI(ID_DELETE_BUTTONS, OnUpdateDeleteButtons) ON_UPDATE_COMMAND_UI(ID_INSERT_BUTTONS, OnUpdateRecoverButtons) void CMainFrame::OnDeleteButtons() { DeleteTBButtons(2, m_nMost - 3); } void CMainFrame::OnRecoverButtons() { RecoverTBButtons(2, m_nMost - 3); }
void CMainFrame::OnUpdateDeleteButtons(CCmdUI* pCmdUI) { pCmdUI->Enable( m_wndToolBar.GetToolBarCtrl().GetButtonCount() == m_nMost ); } void CMainFrame::OnUpdateRecoverButtons(CCmdUI* pCmdUI) { pCmdUI->Enable( m_wndToolBar.GetToolBarCtrl().GetButtonCount() == m_nLeast ); } 6 编译运行"Tb1"
4.2 创建自定义状态栏 分析 “Default” 项目中关于状态栏的代码。不难发现状态栏也 是窗口,该窗口一般分成几个窗格,在每个窗格中可以显示不 同的信息。自动创建的缺省状态栏包括了四个窗格,分别显示 菜单命令提示和键盘的大写、数字、滚屏锁定状态。 状态栏是由 CStatusBar类实现的。状态栏的典型创建步骤: ·定义一个 CStatusBar对象; ·为状态栏的每个窗格定义 ID,并为每个窗格定义了标题字符 串资源(字符串资源和窗格的 ID相同); ·调用CStatusBar::Create创建状态栏窗口; ·调用CStatusBar::SetIndicators 函数分配窗格,并将状态栏的每 个窗格与对应的字符串资源绑定。
4.2.1 利用 AppWizard 自动创建状态栏 使用 AppWizard的缺省选择创建的程序框架能自动创建一个 缺省状态栏。分析程序中与状态栏有关的代码,对于修改原有 的状态栏和创建自定义状态栏都是十分必要的。与缺省状态栏 有关的资源和代码包括: 1CMainFrame类中定义中添加了状态栏对象保护成员: protected: CStatusBarm_wndStatusBar; …
2在 CMainFrame类实现文件中添加了把状态栏分割为窗格的全 程静态数组定义 static UINT indicators[] = { ID_SEPARATOR, // status line indicator ID_INDICATOR_CAPS, ID_INDICATOR_NUM, ID_INDICATOR_SCRL, }; 其中: ·ID_SEPARATOR对应的窗格用于显示菜单命令提示。 ·其他三项用于显示键盘相应的键状态,它们所对应的字符 串在资源 String Table 中被定义为:
STRINGTABLE DISCARDABLE BEGIN … ID_INDICATOR_CAPS "CAP" ID_INDICATOR_NUM "NUM" ID_INDICATOR_SCRL "SCRL" … END ·确定状态栏窗格数目和内容的 indicators由几个和哪些 ID组 成取决于程序的需要。 ·如果 indicators中加入新元素,则要为新元素指定 ID,还要 根据需要,在字符串资源中定义 ID标识的描述字符串。
3创建状态栏窗口 与工具栏一样,状态栏创建操作也是在 CMainFrame::OnCreate 完成的。实现该操作的代码: 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 } 其中 Create和 SetIndicators函数的原型:
BOOL Create( CWnd*pParentWnd,// 父窗口指针 DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_BOTTOM, UINT nID = AFX_IDW_STATUS_BAR /* 状态栏 ID */ ); 其中状态栏样式参数包括如下三种: ·CBRS_TOP Control bar is at top of frame window. ·CBRS_BOTTOM Control bar is at bottom of frame window. ·CBRS_NOALIGN Control bar is not repositioned when the parent is resized. 注意:状态栏不支持浮动。 BOOL SetIndicators( const UINT* lpIDArray, int nIDCount ); 这两个成员函数调用成功,返回 TRUE,否则返回 FALSE。由 于状态栏不支持浮动,所以就不必设置其停靠特性。
4.2.2自定义状态栏 实例 “Sb” 是在实例 “Default” 的基础上对状态栏 m_wndStatusBar 进行了如下修改: ·第一个窗格在保持原有功能的基础上,使它能够显示鼠标在 窗口工作区中移动时的位置信息。 ·将第四个窗格中显示的键状态修改为显示键盘的 <Shift> 键的 状态,即按下 <Shift>键,窗格显示文本信息 “SHIFT”,释放 <Shift> 键,窗格中的文本信息 “SHIFT” 消失。 ·增加第五个窗格用于显示当前时间(时:分:秒)。
1 在 indicators数组中删除 ID_INDICATOR_SCRL,并添加新元素 ID_INDICATOR_SHIFT 和 ID_INDICATOR_CLOCK: static UINT indicators[] = { ID_SEPARATOR, // status line indicator ID_INDICATOR_CAPS, ID_INDICATOR_NUM, ID_INDICATOR_SHIFT, ID_INDICATOR_CLOCK, }; 2 选择菜单命令 View->Resource Symbols,在资源符号对话框中 为 ID_INDICATOR_SHIFT和 ID_INDICATOR_CLOCK定义 ID值。
3 在资源 String Table 中为新增的 ID添加字符串: 4更新时间窗格 实现该功能首先要利用系统定时器产生变化的当前时间,并 将产生的时间转换成格式为“时:分:秒” 的字符串;然后通过调用 CStatusBar::SetPaneText函数将时间字符串显示在第五窗格中。 SetPaneText 的原型如下: BOOL SetPaneText( int nIndex, LPCTSTR lpszNewText, BOOL bUpdate = TRUE );
⑴动态地获取当前时间可以通过定时读取系统当前时间实现,⑴动态地获取当前时间可以通过定时读取系统当前时间实现, 为此可以使用 ClassWizard为 CMainFrame增加系统定时器窗口消 息 WM_TIMER的映射项、响应函数 OnTimer的声明和定义。 ⑵ 在 OnTimer函数中添加操作代码: void CMainFrame::OnTimer( UINT nIDEvent ) { CTime time; time = CTime::GetCurrentTime(); CString s = time.Format( "%H:%M:%S" ); m_wndStatusBar.SetPaneText( m_wndStatusBar.CommandToIndex(ID_INDICATOR_CLOCK), s); CFrameWnd::OnTimer( nIDEvent ); }
⑶ 设置系统定时器 为了使系统能按照要求的时间间隔发出时间中断,需要在 CMainFame构造函数或 OnCreate中调用 CWnd::SetTimer设置能指 定时间间隔发出中断的定时器。 SetTimer 的原型: UINT SetTimer( UINTnIDEvent, UINTnElapse, void (CALLBACK EXPORT* lpfnTimer ) ( HWND, UINT, UINT, DWORD) ); 参数: nIDEvent定时事件标识,一个程序中可以有多个定时器。 nElapse定时器的定时间隔。 lpfnTimer指向自定义定时器设置函数,NULL 表示使用系统 定时器设置函数。
返回: 如果设置成功,返回定时事件标识;否则返回 0。 本例中在 CMainFrame::OnCreate 中添加了如下设置代码: m_nTimer = SetTimer(1, 1000, NULL); // 定时间隔为1000ms 其中 m_nTimer是在 CMainFrame 中添加的数据成员: class CMainFrame public CFrameWnd { … private: UINT m_nTimer; // 用于保存定时器标识。 }
⑷ 已经设置成功的定时器在其所属窗口关闭撤消时,应该调用 CWnd::KillTimer 同时撤消,为此使用 ClassWizard为 CMainFrame增 加主框架窗口关闭消息 WM_CLOSE的映射项、响应函数 OnClose 的声明和定义。 ⑸ 为 OnClose函数添加操作代码: void CMainFrame::OnClose() { KillTimer(m_nTimer); CFrameWnd::OnClose(); }
5 更新 <Shift> 按键状态对应的窗格 该功能是通过添加 ID_INDICATOR_SHIFT的用户界面更新消息 的映射项、响应函数 OnUpdateShift的声明和定义实现的。 完成这些编程只能手工进行,而不能使用 ClassWizard。 ⑴ 在 CMainFrame中加入消息处理函数 OnUpdateShift的原型: //}}AFX_MSG afx_msg void OnUpdateShift(CCmdUI* pCmdUI); DECLARE_MESSAGE_MAP() ⑵ 在 CMainFrame类的消息映射表中加入映射条目: //}}AFX_MSG_MAP ON_UPDATE_COMMAND_UI( ID_INDICATOR_SHIFT, OnUpdateShift) END_MESSAGE_MAP()