510 likes | 700 Views
第 5 章 菜单、 工具栏和状态栏. 河北经贸大学信息技术学院. 教学目标. 了解菜单、工具栏和状态栏的概念及相关类的基本操作; 掌握 Windows 编程中资源的使用; 能够在单文档和对话框应用程序中编程实现常用的菜单、工具栏和状态栏。. 5.1 菜单. 菜单概述 用编辑器设计菜单 菜单类 CMenu 快捷菜单的设计与使用 示例. 菜单. 菜单是 Windows 中最常见的界面元素,是一系列命令的列表。 菜单分为两种: 下拉菜单 快捷菜单(上下文菜单)
E N D
第5章 菜单、工具栏和状态栏 河北经贸大学信息技术学院
教学目标 • 了解菜单、工具栏和状态栏的概念及相关类的基本操作; • 掌握Windows编程中资源的使用; • 能够在单文档和对话框应用程序中编程实现常用的菜单、工具栏和状态栏。
5.1 菜单 • 菜单概述 • 用编辑器设计菜单 • 菜单类CMenu • 快捷菜单的设计与使用 • 示例
菜单 • 菜单是Windows中最常见的界面元素,是一系列命令的列表。 • 菜单分为两种: • 下拉菜单 • 快捷菜单(上下文菜单) • 加速键是键盘上的一个键或几个键的组合,它通常对应于某一条菜单命令或工具按钮命令,它为用户提供了一种快速执行菜单命令或其他某种功能的方法。
用编辑器设计菜单 • 使用菜单编辑器, • 可以增加或删除菜单和菜单项, • 定义菜单标识符ID, • 对菜单进行合理布局, • 设置菜单的初始状态(正常、灰色、加标记等) • 设置菜单提示等。 • 使用AppWizard创建基于SDI的应用程序框架时,会自动创建一个菜单资源:IDR_MAINFRAME • 使用AppWizard创建基于MDI的应用程序框架时,会自动创建两个菜单资源:IDR_MAINFRAME和 IDR_***TYPE(星号表示项目名) • 在菜单编辑器中,可以对AppWizard生成的菜单进行修改,也可以从空白菜单基础上创建需要的菜单
创建下拉菜单的步骤: • 创建菜单资源 • 打开菜单编辑器,编辑菜单:在菜单栏中双击空白方框,弹出[ Menu Item Properties]对话框,设置菜单项属性。 • 为菜单资源选择一个类(视图类或对话框类) • 建立菜单命令消息处理函数 • WM_COMMAND:选择菜单项或使用快捷键时将产生此消息 • UPDATE_COMMAND_UI:更新命令用户接口消息,当菜单在显示之前,会先通过此消息进行更新,从而得到更新后的菜单。
【例5.1】单文档应用程序中菜单的创建和使用 • 在单文档应用程序的默认菜单资源中添加一个“绘图”菜单,通过“绘图”菜单命令在窗口中绘制出不同的椭圆和矩形,程序的运行效果如图 所示。
步骤: 1、创建一个基于SDI的应用程序,项目名为:EX5_1 2、在项目工作区的[Resource View]中,双击菜单资源[IDR_MAINFRAME],打开菜单资源编辑器。 3、在[帮助]菜单前插入一个新菜单[绘图(&D)],并为其添加相应的菜单项,如图所示 Alt+D 激活该菜单
菜单属性设置 Caption ID 提示(Prompt) 椭圆 Pop-up 矩形 Pop-up 清除(&C) ID_DRAW_CLEAR 清除窗口中的图形 100*100 ID_DRAW_ELLIPSE1 绘制一个外接矩形为100*100的椭圆 100*200 ID_DRAW_ELLIPSE2 绘制一个外接矩形为100*200的椭圆 100*100 ID_DRAW_RECT1 绘制一个100*100的矩形 100*200 ID_DRAW_RECT2 绘制一个100*200的矩形
4、为菜单资源选择一个类CEX5_1View 5、使用[MFC ClassWizard],为视图类CEX5_1View添加菜单消息处理函数. Object Ids 消息 消息处理函数 ID_DRAW_CLEAR COMMAND OnDrawClear() ID_DRAW_ELLIPSE1 COMMAND OnDrawEllipse1() ID_DRAW_ELLIPSE2 COMMAND OnDrawEllipse2() ID_DRAW_RECT1 COMMAND OnDrawRect1() ID_DRAW_RECT2 COMMAND OnDrawRect2()
6、为消息处理函数添加代码 绘制一个外接矩形为100*100的椭圆 void CEX5_1View::OnDrawEllipse1() { // TODO: Add your command handler code here CDC *pDC=GetDC(); // 获取窗口设备环境 CRect r, rect; // 定义矩形类对象 GetClientRect(&r); // 获取客户区窗口坐标范围 rect.bottom=r.bottom/2+50; // 设置rect的范围 rect.top=r.bottom/2-50; rect.right=r.right/2+50; rect.left=r.right/2-50; pDC->Ellipse(rect); // 在rect指定的范围内画椭圆 } 50 r.bottom 50
绘制一个100*100的矩形 void CEX5_1View::OnDrawRect1() { // TODO: Add your command handler code here CDC *pDC=GetDC(); // 获取窗口设备 CRect r, rect; // 定义矩形类对象 GetClientRect(&r); // 获取客户区窗口坐标范围 rect.bottom=r.bottom/2+50; // 设置rect的范围 rect.top=r.bottom/2-50; rect.right=r.right/2+50; rect.left=r.right/2-50; pDC->Rectangle(rect); // 在rect指定的范围内画矩形 }
清除菜单项的消息处理函数: void CEX5_1View::OnDrawClear() { // TODO: Add your command handler code here Invalidate(); // 刷新窗口 } 该函数用来使当前视图失效,强制程序重新执行OnDraw()函数以刷新窗口
使用键盘快捷键 加速键也称为键盘快捷键,是一个按键或几个按键的组合,用于激活特定的命令。加速键也是一种资源,它的显示、编辑过程和菜单相似。 为一个菜单项定义快捷键的步骤如下: • 打开项目工作区窗口中的Accelerator的资源项,双击IDR_MAINFRAME,出现如图5.8的加速键资源列表 • 建立新的加速键,双击加速键列表的最下端的空行,弹出如图5.9所示的“Accel Properities”对话框,其中可设置的属性见表5-4。 • 选择添加的“椭圆100*100”菜单项的ID号ID_DRAW_ELLIPSE1,选择“Ctrl”,输入键值“E”。
技术要点: • CRect类:是MFC封装矩形区域操作的一个专用类,其结构与Windows中的RECT结构类似。 • 类型RECT的定义: typedef struct _RECT{ LONG left; LONG top; LONG right; LONG bottom; } RECT; • 成员函数(略) 左上角坐标 右下角坐标
绘制椭圆函数: CDC类的成员函数 BOOL Ellipse (int x1, int y1, int x2, int y2); BOOL Ellipse ( LPCRECT lpRect ); • 绘制矩形函数:CDC类的成员函数 BOOL Rectangle(int x1, int y1, int x2, int y2); BOOL Rectangle( LPCRECT lpRect ); • 参数: x1,y1:表示矩形左上角的坐标 x2,y2:表示矩形右下角的坐标, lpRect:是一个RECT结构或CRect类对象
5.1.3 CMenu类 • 如果想在程序中使用上下文菜单,或者在程序运行中对菜单项进行动态修改,就必须使用MFC的菜单类CMenu • 使用CMenu类可以完成大量复杂的菜单操作:创建、追踪、更新、销毁菜单
CMenu类成员函数 表 5-5 CMenu 的成员 方法 说明 Attach() 把一个标准的 Windows 菜单句柄附加到 CMenu 对象上 CreateMenu() 创建一个空菜单并把它附加到 CMenu 对象上 CreatePopupMenu() 创建一个弹出式菜单并把它附加到 CMenu 对象上 DeleteTempMap() 删除由 FromHandle() 构造函数创建的任何临时 CMenu 对象 DestroyMenu() 去掉附加到 CMenu 对象上的菜单并释放该菜单占有的任何内存 Deatch() 从 CMenu 对象上拆开 Windows 菜单句柄并返回该句柄 FromHandle() 当给定 Windows 菜单句柄时,返回 CMenu 对象指针 m_hMenu: 指定附加给CMenu类对象的窗口菜单的句柄 GetSafeHmenu() 返回由 CMenu 对象封装的菜单句柄成员 ( m_hMenu) LoadMenu() 从可执行文件装入菜单资源并把它附到 Cmenu 对象上 LoadMenuIndirect() 从内存中的菜单模板中装入菜单并把它附到 CMenu 对象上 函数原型在系统目录的AFXWIN.H文件中
DeleteMenu() TrackPopupMenu() 删除某个特定的菜单项(包括附属的级连菜单项) 在一个POINT结构所指定的位置显示一个快捷菜单 菜单项操作函数 方法 说明 AppendMenu() 把一个新项加到给定的菜单的末端 在弹出式菜单中,把一个校验标记放到一个菜单项 CheckMenuItem() 或从一个菜单项中取消一个校验标记 在此组中,把一个单选按钮放到菜单项旁边或从全部 CheckMenuRadioItem() 其它菜单项里取消一个已存在的单选按钮 EnableMenuItem() 去掉 ( 添加 ) 一个菜单项 GetMenuContextHelpId() 检索与菜单结合的帮助上下文 ID GetMenuItemCount() 在弹出式或顶层菜单中获得项数 GetMenuItemID() 获取指定位置的菜单项的标识 GetMenuState() 获得指定菜单项的状态或弹出式菜单中的菜单项数 GetMenuString() 获得指定菜单项的标签 GetSubMenu() 获得指向弹出式菜单的指针 InsertMenu() 在指定位置插入新的菜单项,把其它项向下移 ModifyMenu() 在指定位置改变已存在的菜单项 RemoveMenu() 从指定菜单删除与弹出式菜单结合的菜单项 SetMenuContextHelpID() 设置与菜单有关的帮助上下文 ID SetMenuItemBitmaps() 与菜单项有关的指定校验标记位图 菜单操作方法中只有两个方法用来处理菜单的顶层操作
5.1.4 上下文菜单 • 创建一个具体的上下文菜单,通常有两种方法: • 先创建一个菜单资源,再在程序中将编辑好的资源加载进来 • 利用CMenu类的强大功能,在程序中动态地创建上下文菜单
示例 为实例5-1添加上下文菜单 • 打开项目EX5_1 • 为应用程序添加一个新菜单 • 在项目工作区的[Resource View]中,在[Menu]上右击鼠标,从弹出菜单中选择[Insert Menu]命令添加一个新菜单,设置标识ID为IDR_CONTEXTMENU • 在菜单资源编辑器中制作上下文菜单,使用与绘图菜单相同的ID标识,以便调用相同的消息处理函数
为视图类添加成员变量和消息处理函数 为菜单资源连接一个类CEx5_1View,然后为视图类添加成员变量 Object Ids 消息 消息处理函数 ID_DRAW_CLEAR COMMAND OnDrawClear() ID_DRAW_ELLIPSE1 COMMAND OnDrawEllipse1() ID_DRAW_ELLIPSE2 COMMAND OnDrawEllipse2() ID_DRAW_RECT1 COMMAND OnDrawRect1() ID_DRAW_RECT2 COMMAND OnDrawRect2() CEX7_1View WM_RBUTTONDOWN OnRButtonDown CEX7_1View WM_CONTEXMENU OnContextMenu() 变量 类型 说明 m_bFlag bool 标记是否使用了上下文菜单 m_ConPoint CPoint 记录鼠标右击时相对于窗口的位置 同“绘图”菜单
当用户在视图中右击鼠标时,系统将产生两条消息:当用户在视图中右击鼠标时,系统将产生两条消息: WM_RBUTTONDOWN WM_CONTEXMENU (上下文菜单消息): 对此消息进行处理而得到上下文菜单 afx_msg void OnContextMenu(CWnd* pWnd, CPoint point); afx_msg void OnRButtonDown(UINT nFlags, CPoint point); 右键单击鼠标时的位置,相对于屏幕左上角的位置 右键单击窗口的句柄 右键单击鼠标时的位置,相对于当前窗口左上角的位置
添加程序代码 在视图类构造函数中对成员变量设置初始值 CEX7_1View::CEX5_1View() { // TODO: add construction code here m_bFlag=false; // 上下文菜单未在使用中 } 由于主菜单命令和上下文菜单命令具有相同的ID标识,所以成员变量m_bFlag来标识当前命令是来自主菜单还是上下文菜单。 m_bFlag=true; 表示使用上下文菜单 m_bFlag=false; 表示未使用上下文菜单
鼠标右键按下消息: void CEX5_1View::OnRButtonDown(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default m_ConPoint=point; // 获取鼠标单击时相对于窗口位置的坐标 CView::OnRButtonDown(nFlags, point); }
绘制100*100的内接椭圆: void CEX5_1View::OnDrawEllipse1() { // TODO: Add your command handler code here CDC *pDC=GetDC(); // 获取窗口设备 CRect r, rect; // 定义矩形类对象 if (m_bFlag) { rect.bottom=m_ConPoint.y+50; // 设置rect的范围 rect.top=m_ConPoint.y-50; rect.right=m_ConPoint.x+50; rect.left=m_ConPoint.x-50; m_bFlag=false; } else { GetClientRect(&r); // 获取客户区窗口坐标范围 rect.bottom=r.bottom/2+50; // 设置rect的范围 rect.top=r.bottom/2-50; rect.right=r.right/2+50; rect.left=r.right/2-50; } pDC->Ellipse(rect); // 在rect指定的范围内画椭圆 }
WM_CONTEXTMENU消息处理函数 void CEX5_1View::OnContextMenu(CWnd* pWnd, CPoint point) { // TODO: Add your message handler code here CMenu Drawmenu; // 创建菜单实例 Drawmenu.LoadMenu(IDR_CONTEXTMENU); // 加载菜单资源 m_bFlag=true; // 设置标记,使用上下文菜单 // 将Drawmenu菜单对象中的第一个子菜单载入为弹出菜单 CMenu *pContextmenu=Drawmenu.GetSubMenu(0); // 显示上下文菜单 pContextmenu->TrackPopupMenu( TPM_LEFTALIGN|TPM_RIGHTBUTTON,point.x,point.y,this); Drawmenu.DestroyMenu(); // 销毁菜单 } 成员函数参考教材,不再赘述.
在程序中动态创建上下文菜单 void CEX5_1View::OnContextMenu(CWnd* pWnd, CPoint point) { // TODO: Add your message handler code here CMenu Drawmenu; // 创建菜单实例 m_bFlag=true; // 设置标记,使用上下文菜单 Drawmenu.CreatePopupMenu(); // 创建空弹出菜单 // 添加菜单项 Drawmenu.AppendMenu(MF_ENABLED,ID_DRAW_ELLIPSE1,"椭圆 100*100"); Drawmenu.AppendMenu(MF_ENABLED,ID_DRAW_ELLIPSE2,"椭圆 100*200"); Drawmenu.AppendMenu(MF_SEPARATOR); Drawmenu.AppendMenu(MF_ENABLED,ID_DRAW_RECT1,"矩形 100*100"); Drawmenu.AppendMenu(MF_ENABLED,ID_DRAW_RECT2,"矩形 100*200"); Drawmenu.AppendMenu(MF_SEPARATOR); Drawmenu.AppendMenu(MF_ENABLED,ID_DRAW_CLEAR,"清 除"); // 显示弹出菜单 Drawmenu.TrackPopupMenu( TPM_LEFTALIGN|TPM_RIGHTBUTTON,point.x,point.y,this); Drawmenu.DestroyMenu(); // 销毁菜单 }
示例 用菜单命令调用模式对话框 创建一个带有“计算”菜单的单文档应用程序EX5-2。“计算”菜单中包含“平均成绩”菜单项。当单击该菜单项时,会弹出一个模式对话框,用于计算平均成绩。运行结果如图5.11。
【例5.3】 为对话框添加菜单 (1)添加并定制菜单资源 (2)菜单与对话框关联:在对话框属性页的Menu下拉列表框中选择菜单ID (3)为菜单选择对话框类,之后消息映射,编写消息处理函数代码。
5.2 工具栏CToolBar • 5.2.1 CToolBar类 • 5.2.2 工具栏编辑器 • 5.2.3 工具栏与菜单结合
5.2 工具栏CToolBar 工具栏可以看作是图形化的菜单,是一种更快捷、更有效、更直观的命令输入方式。 当创建SDI/MDI应用程序时,AppWizard不仅创建了缺省菜单,并且创建了缺省的工具栏IDR_MAINFRAME,其相应的位图Toolbar.bmp。 用户可以为缺省工具栏中添加一些按钮,也可以设计和使用自己的工具栏。 • Visual C++创建工具栏的一般步骤如下: • 创建一个工具栏资源; • 构造CToolBar对象; • 调用Create()(或CreateEx())函数创建Windows工具栏并将它与该CToolBar对象连接; • 调用LoadToolBar()函数装入工具栏资源。
7.2.1 CToolBar类 CStatusBar(状态条) CToolBar类有几个兄弟类 COleResizeBar(OLE控制条) 都是用来接收某些 命令输入并向用户 显示状态消息的类 CDialogBar(对话条)
工具条函数简介 (1 )Create()函数 BOOL Create ( CWnd* pParentWnd, //pParentWnd为指向工具条所在父窗口的指针 DWORD dwStyle=WS_CHILD|WS_VISIBLE|CBRS_TOP, // dwStyle为工具条的风格(见下页) UINT nID = AFX_IDW_TOOLBAR //nID表示工具条子窗口的ID号 ); 下述代码生成一工具条,工具条风格为“初始可见”,且放置在窗口“顶部”,工具条窗口的ID号的16进制值为9100: CToolBar m_ToolBar=new CToolBar( ); m_ToolBar.Create(this, WS_VISIBLE |CBRS_TOP,0x9100);
(2) LoadToolBar()函数 BOOL LoadToolBar(LPCTSTR lpszResourceName); //字符串形式定义的资源 BOOL LoadToolBar(UINT nIDResource); //整型形式定义的资源 (3 )SetBarStyle()函数 m_wndToolBar.SetBarStyle(CBRS_TOOLTIPS|CBRS_FLYBY| CBRS_SIZE_DYNAMIC); WS_VISIBLE 使工具条窗口初始可见 CBRS_BOTTOM 初始时将工具条放到窗口底部 CBRS_FLYBY 在状态栏显示命令描述 CBRS_NOALIGN 防止控制条在其父窗口改变大小时被复位 CBRS_TOOLTIPS 鼠标光标在按钮上暂停时,显示工具提示 CBRS_TOP 初始时将工具条放在窗口顶部 CBRS_SIZE_DYNAMIC 工具条的尺寸是可变的
对于CFrame不可用 (4 )工具条的移动 为使用户能够移动工具条,为此,需向工具条及框架窗口发送消息。这可通过调用CToolBar::EnableDocking和CFrame::EnableDocking实现。 二函数原型均如下: void EnableDocking( DWORD dwStyle ); 默认状况下,CToolBar工具条只能被应用程序所移动 实现工具条移动的常用代码: m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); EnableDocking(CBRS_ALIGN_ANY); 用户也可以对工具条进行移动或定位。或者在程序控制下,通过调用CFrameWnd::DockControlBar来移动以及调用 CFrameWnd::FloatControlBar来定位一工具条。 停靠 风格
(5)工具条的显隐控制 由于工具条是一个窗口,它的显示或隐藏可以通过其父类CWnd的成员函数来实现 显示或隐藏一个工具条 void CWnd:: ShowControlBar( CControlBar*pBar, BOOL bShow, BOOL bDelay ); 为TRUE,显示;为FALSE,隐藏 在改变工具条状态前要通过函数CWnd::GetStyle获取当时工具条的状态 DWORD GetStyle( ) const; 为TRUE,延迟显示工具条;为FALSE,立即显示
5.2.2 工具栏编辑器 (1) 加入工具条按钮 可以利用VC所提供的绘图工具,直接进行按钮的编缉,这主要用来编缉自己的按钮,对于已经存在的图标,如果要把它作为下一个按钮,可以先加入一个ICON资源,再通过拷贝和粘贴来放到Toolbar上。 (2)删除工具条按钮 删除按钮要把该按钮拖出工具条以外。 (3)移动工具条按钮 是用鼠标将要移动的按钮拖动到工具条上需要的位置。 (4)插入空格 前插空格/后插空格/删除空格 (5)工具栏按纽属性设置
5.2.3 工具栏与菜单结合 • 使它们结合的方法是在工具栏按钮的属性对话框中将按钮的ID号设置为相关联的菜单项ID。
5.3 状态栏 • 5.3.1 CStatusBar类 • 5.3.2 CStatusBar类的使用方法 • 5.3.3 状态栏的常用操作 • 5.3.4 示例
5.3 状态栏 CStatusBar P222 • 状态栏可以随时为用户提供当前程序的状态信息,它即不接受输入也不产生命令消息。 • 状态栏结构: • 提示信息窗格 • 指示器信息窗格 • 应用程序框架自动生成标准状态栏,状态栏的格式由MainFrm.cpp文件中的静态数组indicators所定义,CStatusBar类成员函数SetIndicators将调用该数组生成状态栏。 static UINT indicators[] = { ID_SEPARATOR, //信息窗格 ID_INDICATOR_CAPS, //Caps Lock指示器 ID_INDICATOR_NUM, //Num Lock指示器 ID_INDICATOR_SCRL, // Scoll Lock指示器 };
状态栏的常用操作 • 增加或减少窗格 如果要对状态栏进行改变,可以对此数组元素进行修改、增加或删除。 • 在状态栏上显示信息 (1)CStatusBar类 SetPaneText(nIndex,lpszNewText) (2)CWnd::SetWindowText()设置第1个窗格的文本 (3) 手动添加状态栏窗格的ON_UPDATE_COMMAND_UI事件的消息映射,添加afx_msg void类型的带参消息处理函数 OnUpdate***(CCmdUI* pCmdUI) • 改变状态栏的风格 SetPaneStyle(int nIndex, UINT nStyle); SetPaneInfo(int nIndex,UINT Id, UINT nStyle,int cxWidth); P224表7-11风格类型 示例一 P224-225 使用SetPaneText()函数 示例二 使用ON_UPDATE_COMMAND_UI事件的消息
实例:为实例5_1添加状态栏信息 • 程序运行中会在状态栏显示系统时间,[Insert]键是否被按下等状态,效果如下:
步骤: 1、打开EX5_1项目 2、在资源编辑器的串表中添加以下字符串资源 ID Value Caption ID_INDICATOR_X X坐标值 ID_INDICATOR_Y Y坐标值 ID_INDICATOR_TIME 00:00:00 3、打开MainFrm.cpp文件,修改数组indicators如下: • static UINT indicators[] = • { • ID_SEPARATOR, // status line indicator • ID_INDICATOR_X, • ID_INDICATOR_Y, • ID_INDICATOR_CAPS, • ID_INDICATOR_NUM, • ID_INDICATOR_SCRL, • ID_INDICATOR_TIME, • };
4. 在CEx5_1View类中加入WM_MOUSEMOVE消息处理函数,并添加代码。 • void C Ex5_1View::OnMouseMove(UINT nFlags, CPoint point) • { • // TODO: Add your message handler code here and/or call default • CMainFrame *pFrame=(CMainFrame*)AfxGetApp()->m_pMainWnd ; • CStatusBar* pStatus=&pFrame->m_wndStatusBar ; • CString str; • if (pStatus) • { • str.Format("X=%d",point.x); • pStatus->SetPaneText(1,str); • str.Format("Y=%d",point.y); • pStatus->SetPaneText(2,str); • } • CView::OnMouseMove(nFlags, point); • }
5. 将类CMainFrame中的保护型状态栏对象m_wndStatusBar修改为公共变量。 • 6. 在Ex_SDIMenuView.cpp文件的开始处增加下列语句: • #include “MainFrm.h” • 7.在CMainFrame类的OnCreate函数中,设置定时器,代码如下: • int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) • { …… • SetTimer(1,1000,NULL); // 设置定时器 • return 0; • }
8. 为CMainFrame类映射WM_TIMER消息的处理函数,并添加代码如下: • void CMainFrame::OnTimer(UINT nIDEvent) • { • // TODO: Add your message handler code here and/or call default • CTime tmCurr; • CString strTime; • tmCurr=CTime::GetCurrentTime(); //获取系统当前时间 • strTime=tmCurr.Format("%H:%M:%S"); • // 设置状态栏ID_INDICATOR_TIME窗格文本内容 • m_wndStatusBar.SetPaneText( • m_wndStatusBar.CommandToIndex(ID_INDICATOR_TIME), • strTime); • CFrameWnd::OnTimer(nIDEvent); • } • 9. 编译并运行。
习题五 • 1. 填空题 • 2. 选择题 • 3. 简答题 • 4. 操作题