4. 一个菜单栏可以有若干个子菜单,一个子菜单又可以有若干个菜单项等。对菜单栏的子
菜单由左至右建立从0开始的索引。对特定子菜单的菜单项由上至下建立了从0开始的索引。访问子菜单和菜单项均可以通过其索引或标识(如果有标识的话)进行。 相关重要函数:
CMenu* GetMenu( ) ;//CWnd::GetMenu得到窗口菜单栏对象指针。
CMenu* GetSubMenu( ) ;//CMenu::GetSubMenu获得指向弹出菜单对象指针 UINT CheckMenuItem( );//CMenu::CheckMenuItem 添加选中标识
BOOL SetDefaultItem();//CMenu::SetDefaultItem 为指定菜单设置缺省菜单项
BOOL SetMenuItemBitmaps( );//CMenu::SetMenuItemBitmaps 设置位图标题菜单。 UINT EnableMenuItem();//CMenu::EnableMenuItem使菜单项有效,无效,或变灰。 BOOL SetMenu( CMenu* pMenu );//CWnd::SetMenu在当前窗口上设置新菜单或移除菜单。
HMENU Detach( );//CMenu::Detach;断开一个菜单资源与相关的类对象句柄关联,可以定义局部对象,在使用完后调用Detach函数,则不会因为局部对象影响使用
说明:
1)在计算子菜单菜单项的索引的时候,分隔栏符也算索引的。
2)int GetSystemMetrics()获取系统信息度量。可以用它来获取菜单标题的尺寸(后面还会使用到获取屏目尺寸)从而设置位图标题菜单中位图的大小。
3)在MFC中MFC为我们提供了一套命令更新机制,所有菜单项的更新都是由这套机制来完成的。所以要想利用CMenu::EnableMenuItem来自己控制菜单使用或不使用变灰等,必须要在CMainFrame的构造函数中将变量m_bAutoMenuEnable设置为FALSE。
EXAMPLE:
CMenu menu;//定义为局部对象
menu.LoadMenu(IDR_MAINFRAME); SetMenu(&menu);
menu.Detach();// 这里menu对象作为一个局部对象。使用Detach()从menu对象中分离窗口菜单句柄,从而当menu对象析构的时候窗口菜单资源不随之销毁。 5. 命令更新机制:
菜单项状态的维护是依赖于CN_UPDATE_COMMAND_UI消息,谁捕获CN_UPDATE_COMMAND_UI消息,MFC就在其中创建一个CCmdUI对象。
在后台操作系统发出WM_INITMENUPOPUP消息,然后由MFC的基类如CFrameWnd接管并创建一个CCmdUI对象和第一个菜单项相关联,调用对象成员函数DoUpdate()(注:这个函数在MSDN中没有找到说明)发出CN_UPDATE_COMMAND_UI消息,这条消息带有指向CCmdUI对象的指针。此后同一个CCmdUI对象又设置为与第二个菜单项相关联,这样顺序进行,直到完成所有菜单项。
更新命令UI处理程序仅应用于弹出式菜单项上的项目,不能应用于永久显示的顶级菜单项目。 说明:
1)可以手工或用ClassWizard来给菜单项添加UPDATE_COMMAND_UI消息响应,利用响应函数中传进来的CCmdUI对象指针可完成设置菜单项可使用,不可使用,变灰,设置标记菜单等操作。
6,如果要想让工具栏上的某个图标与菜单项的某个菜单相关联,只需要将图标的ID设置为该菜单项的ID。
工具栏图标的索引记数顺序是:从做至右从0开始,分隔符也算索引号。
7,利用向项目中添加VC的POPMENU控件:Project->Add to Project->Components and Controls..
系统增加的内容:A,一个菜单资源;B,在派生View类中增加了OnContextMenu()函数 说明:
1)CWnd::OnContextMenu Called by the framework when the user has clicked the right mouse button (right clicked) in the window. You can process this message by displaying a context menu using the TrackPopupMenu.
2)BOOL TrackPopupMenu( UINT nFlags, int x, int y, CWnd* pWnd, LPCRECT lpRect = NULL );
//CMenu::TrackPopupMenu Displays a floating pop-up menu at the specified location and tracks the selection of items on the pop-up menu. A floating pop-up menu can appear anywhere on the screen.
8,利用调用TrackPopupMenu函数,手工添加弹出菜单: 1)用资源管理器添加一个菜单资源
2)在鼠标右键消息响应函数中,加载菜单资源,并获得要显示的子菜单指针,并用该指针调用TrackPopupMenu函数便完成任务(但要注意:鼠标响应函数传进来的坐标是客户区坐标,而TrackPopupMenu函数中使用的是屏幕坐标,在调用TrackPopupMenu前要调用ClientToScreen客户区坐标到屏幕坐标的转换) 事例代码: CMenu menu;
menu.LoadMenu(IDR_MENU1);
CMenu *pPopup=menu.GetSubMenu(0); ClientToScreen(&point);
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y,this); 说明:
CWnd::ClientToScreen(..);//将一个坐标点或一个矩形区域坐标转换成屏幕坐标。 CMenu::TrackPopupMenu(..);//在指定位置以指定的方式显示弹出菜单。 CWnd::ScreenToClient(..);
//Converts the screen coordinates of a given point or rectangle on the display to client coordinates.
9,当弹出菜单属于框架窗口的时候(可在TrackPopupMenu函数参数中设置),弹出菜单上的消息,在路由的时候,仍然遵循View-DOC-MainFrame-APP的响应顺序。
10,动态菜单编程:
所有的资源对象都有一个数据成员保存了资源的句柄。
CMenu::AppendMenu //Appends a new item to the end of a menu.
CMenu::CreatePopupMenu //Creates an empty pop-up menu and attaches it to a CMenu object.
CMenu::InsertMenu
//Inserts a new menu item at the position specified by nPosition and moves other items down the menu.
CMenu::GetSubMenu //Retrieves a pointer to a pop-up menu.
CWnd::GetMenu //Retrieves a pointer to the menu for this window. CMenu::DeleteMenu //Deletes an item from the menu.
11,手动给动态菜单项添加响应函数: 在Resource.h中可以添加资源的ID 在头文件中写消息函数原型
在代码文件中添加消息映射和添加消息响应函数 说明:
可以先创建一个临时的菜单项,设置它的ID和动态菜单项的一致,然后对它用向导进行消息响应,然后删除临时菜单。
再在代码文件中把消息映射放到宏外(注意一定要放到宏外面,因为CLASSWIZARD发现菜单删除了,同时要把其宏对里的消息映射也删除掉的)
12,CWnd::DrawMenuBar
//Redraws the menu bar. If a menu bar is changed after Windows has created the window, call this function to draw the changed menu bar
CWnd::GetParent //get a pointer to a child window’s parent window (if any). CWnd::Invalidate //注意其参数的作用
13,集合类:
CStringArray,CStringArray,CDWordArray,CPtrArray,CStringArray,CUIntArray,CWordArray 其中成员函数: CArray::GetAt CArray::Add
14,命令消息是到OnCommand函数的时候完成路由的。
由于CWnd::OnCommand 是个虚函数,可以在框架类中重写OnCommand函数,从而可以截获菜单消息使它不再往下(VIEW类)路由。 例:
BOOL CMainFrame::OnCommand(WPARAM wParam, LPARAM lParam) {
// TODO: Add your specialized code here and/or call the base class int MenuCmdId=LOWORD(wParam);//取命令ID
CMenu2View *pView=(CMenu2View*)GetActiveView();//获取当前VIEW类指针 if(MenuCmdId>=IDM_PHONE1 && MenuCmdId
CClientDC dc(pView);
dc.TextOut(0,0,pView->m_strArray.GetAt(MenuCmdId-IDM_PHONE1)); return TRUE;
//函数返回,避免调用CFrameWnd::OnCommand函数,在CFrameWnd::OnCommand中截获的消息会交由VIEW类处理 }
return CFrameWnd::OnCommand(wParam, lParam); //调用基类OnCommand函数,在CFrameWnd::OnCommand中截获的消息会交由VIEW类处理 }
15,LOWORD与HIWORD宏 WORD LOWORD(
DWORD dwValue // value from which low-order word is retrieved );
WORD HIWORD(
DWORD dwValue // value from which high-order word is retrieved );
//The LOWORD macro retrieves the low-order word from the given 32-bit value. //The HIWORD macro retrieves the high-order word from the given 32-bit value.
16,CFrameWnd::GetActiveView
CView* GetActiveView( ) const;//获取当前视窗口指针(单文档框架中) 源文件是单独参与编译的。
Lesson7: 对话框编程
1. Windows应用程序工作的基本流程是从用户那里得到数据,经过相应的处理之后,现把
处理结果输出到屏幕,打印机或者绵输出设备。这就需要用到Windows应用程序的用户接口对话框。对话框就是一个窗口,它不公可以接收消息,而且还可以被移动和关闭,甚至可以在它的客户区中进行绘图。相当于一个窗口,在它上面能够旋转各种标准控件和扩展控件。都是由CWnd类派生来
2. 对话框的类型:模态(Model)对话框和非模态(Modeless)对话框
模态对话框:指当其显示时,程序会暂停执行,直到关闭这个模态对话框后,才能继续执行程序中其它任务。当一个模态对话框打开时,用户只能与该对话框进行交互,而其它用户界面对象接收不到输入信息。
非模态对话框:当其显示时,允许执行程序中其它任务,而不用关闭这个对话框。 在MFC中,对资源的操作通常都是通过一个与资源相关的类来完成。对话框资源对应CDialog基类。
3. 在对话框资源界面,选择[View]->[ClassWizard]菜单命令,(也可以新建的对话框资源上
双击鼠标左键),选择一个基类,创建关于它的类。其中一般有两个函数一个是构造函数(可用于初始化成员变量),另外一个是DoDataExchange主要用来完成对话框数据的交换和校验,要想在其它窗口的事件中显示该对话框就涉及到创建对话框的模式(模态与非模态)
模态对话框的创建:
创建模态对话框要调用CDialog类的成员函数:DoModel(),创建一个模态对话框,其返回值作为CDialog类的另一个成员函数:EndDialog的参数,后者的功能就是关闭模态对话框。
Void CMyboleView::OnDialog(){ CTestDlg dlg;//视类中源文件要包含这个类的头文件 dlg.DoModal();//创建一个模态对话框, }
非模态对话框的创建:
需要利用CDialog类的Create成员函数。
BOOL Create(LPCTSTR lpszTemplateName, CWnd* pParaentWnd = NULL); BOOL Create(UINT nIDTemplate, Cwnd* pParentWnd = NULL); lpszTemplateName对话框模板的名称,nIDTemplate对话框模板的ID,pParentWnd对话框的父窗口,如果是NULL则父窗口就是主应用程序窗口
注意:当创建非模态对话框时,还需要调用ShowWindow函数显示对话框,而模态的不需要