1、菜单工具栏状态栏菜单、工具栏和状态栏一、菜单1. 新建一个单文档SDI工程1MiniCAD,在原菜单右侧添加“绘图”子菜单:画线 (&L) t Ctrl+L 画一条直线n画线菜单项名 热键 加速键(快捷键) 状态栏提示 工具栏图标提示实现上述菜单功能。2. 概念:菜单栏、菜单、子菜单、菜单项、分隔条(Separator)菜单栏从左到右是从0开始的索引,菜单项由上至下也是从0开始的索引,访问子菜单和菜单项均通过其索引或标识ID进行。在计算菜单项的索引的时候,分隔栏Separator也要计算在内。相关重要函数:CMenu* GetMenu() ; /得到窗口菜单栏对象指针。CMenu* GetSu
2、bMenu(4) ;/获得指向弹出菜单对象指针UINT CheckMenuItem(); /在菜单项前面打勾BOOL SetDefaultItem(); /使菜单项变粗变黑UINT EnableMenuItem();/使菜单项有效,无效,或变灰。BOOL SetMenuItemBitmaps( );/设置位图菜单。BOOL SetMenu( CMenu* pMenu );/在当前窗口上设置新菜单或移除菜单。HMENU Detach( ); /解除捆绑示例:a. 在View类中,使菜单项“普通模式”成为打勾状态:GetParent()-GetMenu()-GetSubMenu(4)-CheckM
3、enuItem(ID_DRAW_NONE, MF_BYCOMMAND | MF_CHECKED); b. 在CMainFrame:OnCreate()中,使菜单项“普通模式”成为默认菜单: GetMenu()-GetSubMenu(4)-SetDefaultItem(ID_DRAW_NONE); c. 在CMainFrame:OnCreate()中,使菜单项“新建”变成灰色,不可用状态:/禁止“打印预览”菜单项: /EnableMenuItem()需要将CFrameWnd:m_bAutomenuEnable设置为FALSE,/如果该数据成员为TRUE(缺省值),工作框将自动地禁止没有/ON_C
4、OMMAND或者ON_UPDATE_COMMAND_UI的菜单项。 m_bAutoMenuEnable = FALSE; GetMenu()-GetSubMenu(0)-EnableMenuItem(6, MF_BYPOSITION | MF_DISABLED | MF_GRAYED); d. 在CMainFrame:OnCreate()中,给Save As菜单项增加图标: CString str; str.Format(x=%d,y=%d, GetSystemMetrics(SM_CXMENUCHECK), GetSystemMetrics(SM_CYMENUCHECK); MessageB
5、ox(str); CBitmap bitmap; bitmap.LoadBitmap(IDB_BITMAP1); GetMenu()-GetSubMenu(0)-SetMenuItemBitmaps(3, MF_BYPOSITION, &bitmap, &bitmap); bitmap.Detach(); /使HBITMAP和CBitmap解除捆绑,否则会使SetMenuItemBitmaps失效。 说明:int GetSystemMetrics()获取系统信息度量。可以用它来获取菜单标题的尺寸从而设置位图标题菜单中位图的大小。 e. 在CMainFrame:OnCreate()中,移除/增加
6、菜单 CMenu *pMenu = this-GetMenu(); this-SetMenu(NULL); /移除菜单 this-SetMenu(pMenu); /增加菜单3. 在资源管理器中设置加速键。然后在CApp类的InitInstance()中加载快捷键,使定义的Ctrl+L等起作用:HACCEL hAccelTable = LoadAccelerators(theApp.m_hInstance, MAKEINTRESOURCE(IDR_MAINFRAME);4. 菜单消息传递顺序:View类-Doc类-CMainFrame类-App类。菜单消息一旦在其中一个类中响应则不再在其它类中查
7、找响应函数。5. 使用TrackPopupMenu函数,添加右键弹出菜单:1)用资源管理器添加一个菜单资源,也可以利用主菜单中的某个子菜单作为要弹出的菜单。2)在鼠标右键消息响应函数中,加载菜单资源,并获得要显示的子菜单指针,并用该指针调用TrackPopupMenu函数便完成任务(但要注意:鼠标响应函数传进来的坐标是客户区坐标,而TrackPopupMenu函数中使用的是屏幕坐标,在调用TrackPopupMenu前要调用ClientToScreen客户区坐标到屏幕坐标的转换),如:void CMiniCADView:OnRButtonUp(UINT nFlags, CPoint point
8、) /CMenu menu; /menu.LoadMenu(IDR_MAINFRAME); /CMenu *pPopup=menu.GetSubMenu(4); /ClientToScreen(&point); /pPopup-TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, GetParent(); CView:OnRButtonUp(nFlags, point);3) 可用WM_CONTEXTMENU消息替换在鼠标右键消息响应函数来完成TrackPopupMenu的工作。如:void CMiniCADView
9、:OnContextMenu(CWnd* pWnd, CPoint point) /CMenu menu; /menu.LoadMenu(IDR_MAINFRAME); /CMenu *pPopup = menu.GetSubMenu(4); /pPopup-TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, GetParent(); GetParent()-GetMenu()-GetSubMenu(4)-TrackPopupMenu( TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.
10、x, point.y, GetParent();6. 动态菜单编程: 创建动态菜单。常用函数有:CMenu:CreatePopupMenu /创建一个Popup菜单,如“电话本”CMenu:DrawMenuBar /绘制菜单CMenu:AppendMenu /给菜单增加一项,查MSDN,注意nFlags参数的用法如:GetParent()-GetMenu()-AppendMenu(MF_POPUP, (UINT)m_menu.m_hMenu, 电话本);m_menu.AppendMenu(MF_STRING, m_nIndex + IDM_PHONE1, 张三); 为动态菜单添加响应函数:(注
11、意,不是自定义消息)首先在resource.h中定义菜单ID,如:#define IDM_PHONE1 32777#define IDM_PHONE2 32778 第二,消息映射,如:ON_COMMAND(IDM_PHONE1, OnPhone1)ON_COMMAND(IDM_PHONE2, OnPhone2) 第三,定义菜单响应函数,如:afx_msg void OnPhone1();afx_msg void OnPhone2(); 第四,实现菜单响应函数。示例:void CMiniCADView:OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) /
12、 TODO: Add your message handler code here and/or call default if (nChar = 13) /回车 m_nIndex+; /m_nIndex初值为-1 if (0 = m_nIndex) /说明“电话本”菜单项还没有创建,则创建之 m_menu.CreatePopupMenu(); this-GetParent()-GetMenu()-AppendMenu(MF_POPUP, (UINT)m_menu.m_hMenu, 电话本); GetParent()-DrawMenuBar(); m_menu.AppendMenu(MF_ST
13、RING, m_nIndex + IDM_PHONE1, m_strLine.Left(m_strLine.Find( ); /将记录保存进字符串数组 m_strArray.Add(m_strLine); /CStringArray /清空, 清屏, 为输入下一个人的号码做好准备 m_strLine = ; this-Invalidate(); /清屏 else CClientDC dc(this); m_strLine += (char)nChar; dc.TextOut(10, 10, m_strLine); CView:OnChar(nChar, nRepCnt, nFlags);voi
14、d CMiniCADView:OnPhone1() CClientDC dc(this); dc.TextOut(10, 10, m_strArray0);void CMiniCADView:OnPhone2() CClientDC dc(this); dc.TextOut(10, 10, m_strArray1);二、工具条编辑工具栏资源:在资源管理视图中,打开ToolBar目录。新建一个工具条资源IDR_TOOLBAR1。 如下图:工具条一般是和菜单相关联的,将工具栏上的某个图标的ID设置为菜单项的ID即可。工具栏图标的索引记数顺序也是从左到右,由0开始,分隔符也算索引号。CToolBar
15、属于控制栏中的一种,由CControlBar派生。一般在CMainFrame:OnCreate函数中创建工具栏,分2个步骤:先用CToolBar:Create建立工具条对象,建立工具条窗口句柄。然后CToolBar:LoadToolBar加载工具栏资源技巧:要增加一个新的m_wndToolBar1,可以在CMainFrame:OnCreate中,复制m_wndToolBar的相关代码,将m_wndToolBar改成m_wndToolBar1,将资源IDR_MAINFRAME改成IDR_TOOLBAR1即可。主要函数: CreateEx函数:如果dwCtrlStyle=0,则工具栏为VC5以前的
16、凸起风格。dwStyle 包含了丰富的工具栏风格CBRS_SIZE_DYNAMIC和CBRS_SIZE_FIXED是两个相反的风格。 CBRS_SIZE_DYNAMIC是动态尺寸的,在漂浮时可拖拉改变尺寸。CBRS_SIZE_FIXED在漂浮时是紧凑的,无法拖拉改变尺寸。CBRS_GRIPPER风格包含一个突起的掐子,使嵌入的工具栏更方便的拖。CBRS_TOOLTIPS风格使鼠标在工具按钮上方时,可以现实黄色小提示。 DockControlBar 停靠 FloatControlBar 浮动 ShowControlBar 显示三、再回首菜单栏,往事不再依旧:UPDATE_COMMAND_UI消息
17、改变了这一切。增加菜单:查看-绘图栏,添加消息ON_COMMAND(ID_VIEW_DRAWBAR, OnViewDrawbar):void CMainFrame:OnViewDrawbar() ShowControlBar(&m_wndToolBar1,!m_wndToolBar1.IsWindowVisible(), FALSE);继续添加消息ON_UPDATE_COMMAND_UI(ID_VIEW_DRAWBAR, OnUpdateViewDrawbar):void CMainFrame:OnUpdateViewDrawbar(CCmdUI *pCmdUI) pCmdUI-SetChec
18、k(m_wndToolBar1.IsWindowVisible();菜单项状态的维护是基于UPDATE_COMMAND_UI消息,谁捕获该消息,MFC就为谁创建一个CCmdUI对象。可以手工或用ClassWizard来给菜单项添加UPDATE_COMMAND_UI消息响应。在OnUpdatexxx中用CCmdUI控制菜单项可用、不可用,变灰,打勾等操作。只能设置,而不能获取。为菜单ID_DRAW_NONE, ID_DRAW_LINE, ID_DRAW_RECT, ID_DRAW_ELLIPSE添加UPDATE_COMMAND_UI消息,写入SetCheck代码,同时去掉ON_COMMAND中起
19、打勾作用的代码,再次运行,会发现,绘图栏上对应的按钮处于被按下状态了。对用户来说,就更加直观了。修改后的部分代码如下:void CMiniCADView:OnDrawNone() m_nDrawType = 0;void CMiniCADView:OnDrawLine() m_nDrawType = 1;void CMiniCADView:OnUpdateDrawNone(CCmdUI* pCmdUI) pCmdUI-SetCheck(0 = m_nDrawType);void CMiniCADView:OnUpdateDrawLine(CCmdUI* pCmdUI) pCmdUI-SetCh
20、eck(1 = m_nDrawType);绘图栏上的按钮被按下的效果如下图所示:四、状态栏上面的工具栏可以有多个,状态栏一般只有一个。在CStatusBar中,常用的状态栏操作函数有:/Create:创建CStatusBarSetIndicators:设置状态条上指示器CommandToIndex:获取IndexSetPaneText:设置指示器文字SetPaneStyle:设置指示器风格SetPaneInfo:设置指示器属性如下代码在状态栏中增加了一个显示当前时间的指示器:a. 在String资源中添加IDS_TIMER 23:59:59的定义, 不要ID_INDICATOR_TIMER,否
21、则不显示时间b. 在MainFrm.cpp中的indicators数组中添加IDS_TIMERc. 在MainFrm.cpp中OnCreate()中添加 /设置时间栏 CTime t = CTime:GetCurrentTime(); CString str = t.Format(%H:%M:%S); int index = m_wndStatusBar.CommandToIndex(IDS_TIMER); m_wndStatusBar.SetPaneText(index, str); this-SetTimer(123, 1000, NULL); /每秒更新一次时间栏d. 在OnTimer(
22、)中添加上述更新时间的代码五、完善MiniCAD,使其具有图形保持功能。 上面的MiniCAD绘图后,如果改变一下窗口大小,就会擦掉所绘的图形。这是因为我们的绘图代码没有写在OnDraw函数中,而当窗口重绘(WM_PAINT)时,只会重绘OnDraw中代码所写的绘图功能;但是上述工程在OnDraw中没有写任何绘图代码,因此,WM_PAINT时就擦掉了在OnLButtonUp等事件中绘制的图形。 解决思路:将用户绘制的一个个图形都保存起来,然后在OnDraw中一个个的重绘出来。1、定义一个CShape类,用于表示用户所画图形的数据结构,包括图形类型、起点、终点和颜色。class CShape p
23、ublic: UINT m_nDrawType; /绘图类型0不绘图1直线2矩形3椭圆 CPoint m_ptBegin; /起点 CPoint m_ptEnd; /终点 COLORREF m_color; /颜色 CShape(); CShape(UINT nDrawType, CPoint ptBegin, CPoint ptEnd, COLORREF m_color) this-m_nDrawType = nDrawType; this-m_ptBegin = ptBegin; this-m_ptEnd = ptEnd; this-m_color = color; ; virtual C
24、Shape();2、定义一个CMiniCADView成员变量CPtrArray m_ptrArray,用于保存所绘制的一个个图形。在OnLButtonUp最后面,输入以下代码:void CMiniCADView:OnLButtonUp(UINT nFlags, CPoint point) /. /保存当前图形 /CShape shape(m_nDrawType, m_ptBegin, m_ptEnd); /m_ptrArray.Add(&shape); /这种方式保存不了真正的数据,因为shape析构时就销毁了 CShape *pShape = new CShape(m_nDrawType,
25、m_ptBegin, m_ptEnd, m_color); m_ptrArray.Add(pShape); CView:OnLButtonUp(nFlags, point);3、在OnDraw中进行绘图:#include Shape.h void CMiniCADView:OnDraw(CDC* pDC) CMiniCADDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); / TODO: add draw code for native data here /保存老的画笔和画刷,用于后面的恢复。 CPen *pOldPen = pDC-GetCurre
26、ntPen(); CBrush *pOldBrush = pDC-GetCurrentBrush(); /透明画刷 CBrush *pBrush = CBrush:FromHandle(HBRUSH):GetStockObject(NULL_BRUSH); pDC-SelectObject(pBrush); for (int i = m_ptrArray.GetSize() - 1; i = 0; i-) CShape *pShape = (CShape *)m_ptrArray.GetAt(i); /设置画笔颜色:m_color色 CPen pen(PS_SOLID, 1, pShape-m
27、_color); pDC-SelectObject(&pen); /开始绘图 if (pShape-m_nDrawType = 1) /画线 pDC-MoveTo(pShape-m_ptBegin); pDC-LineTo(pShape-m_ptEnd); else if (pShape-m_nDrawType = 2) /画矩形 pDC-Rectangle(pShape-m_ptBegin.x, pShape-m_ptBegin.y, pShape-m_ptEnd.x, pShape-m_ptEnd.y); else if (pShape-m_nDrawType = 3) /画椭圆 pDC-
28、Ellipse(pShape-m_ptBegin.x, pShape-m_ptBegin.y, pShape-m_ptEnd.x, pShape-m_ptEnd.y); /恢复 pDC-SelectObject(pOldBrush); pDC-SelectObject(pOldPen);4、其他:AfxGet. SetCursorvoid CMiniCADView:OnMouseMove(UINT nFlags, CPoint point) /设置鼠标位置状态栏 /#include MainFrm.h /public: CToolBar m_wndStatusBar CMainFrame *p
29、MainFrame = (CMainFrame *)AfxGetMainWnd(); CString sPos; sPos.Format(%d, %d, point.x, point.y); int index = pMainFrame-m_wndStatusBar.CommandToIndex(IDS_MOUSEPOS); pMainFrame-m_wndStatusBar.SetPaneText(index, sPos); /设置绘图时的光标/ :SetClassLong(m_hWnd, GCL_HCURSOR, (LONG):LoadCursor(NULL, m_nDrawType = 0 ? IDC_ARROW : IDC_CROSS); SetCursor(:LoadCursor(NULL, m_nDrawType = 0 ? IDC_ARROW : IDC_CROSS); 作业:在状态栏添加一个鼠标位置指示器,以显示鼠标当前的位置。
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1