关于菜单操作的部分知识点

来源:互联网 发布:淘宝视频空间地址 编辑:程序博客网 时间:2024/04/30 10:46

CWinAPP 类继承CWinThread::CCmdTarget()::CObject(CCmdTarget和CWnd的最顶级父类)
所以CWinApp没有继承CWnd类的,从而没有实现MessageBox
  当然在CWinApp中可以用afxMessageBox代替MessageBox是MFC中的全局API函数

int AfxMessageBox(
LPCTSTR lpszText,
UINT nType = MB_OK,
UINT nIDHelp = 0 );

int AFXAPI AfxMessageBox(
UINT nIDPrompt,
UINT nType = MB_OK,
UINT nIDHelp = (UINT) -1 );

菜单的某个弹出项事件在
CMainFrame
CApp
CDoc
CView
中都添加相同的点击响应事件:
运行程序后,响应的顺序是:
CView
CDoc
CMainFrame
CApp    


标准消息:除了WM_COMMAND之外,所以以WM_开头的消息,
           CWnd派生出来的类都可以接收到这类消息(包括了CFrame、CDialog、CView)也可以接收命令消息

命令消息:来自菜单、加速键或工具栏按钮的消息
          消息方式都以WM_COMMAND呈现。
          在MFC中通过菜单项的ID来区分不同的命令消息;
          在SDK中,通过消息的wParam参数来识别
           CCmdTarget派生的类都可以接收这类消息(包括了CWinApp、CDocument)

通告消息:和命令消息类似,由控件产生的消息

MFC和SDK的区别
sdk是最底层的函数库,mfc对sdk进行了封装
sdk是用C写的,,mfc是用C++写的
最重要的是MFC实现了DOC/VIEW结构,是MFC的最大特色

DOC/view结构其实就是MVC(模型、视图、控制器)结构的精简版
有效的让文档和视图进行代码分离

命令消息的路由:
当一个命令消息下来的时候,,最先接收到信息进行处理的就是CFrame类,然后CFrame类交给子窗口
如果view类也没有信息就交给CDoc文档类
如果CDoc类也没有信息就交给CView类,然后再交还给CFrame类
最后交给CApp类处理


如何创建标记菜单项:
GetMenu
GetSubMenu
CheckMenuItem(UINT nIDCheckItem,UINT nCheck)
如果第二个参数是MF_BYCOMMAND,则第一个参数是某一项的ID
如果第二个参数是MF_POSITION ,则第一个参数是某一项的索引

在CFrmae里OnCreate()加 GetMenu()->GetSubMenu (0)->CheckMenuItem(0,MF_BYPOSITION|MF_CHECKED);

如何创建缺省菜单项
Bool  SetDefaultItem(UINT uItem,Bool fBypos=false);
如果是false 第一参数是菜单项的ID
如果是ture 第一参数是菜单项的索引
 GetMenu()->GetSubMenu(0)->SetDefaultItem(1,true);

如何创建图形标记菜单
SetMenuItemBitmaps(UINT nPosition,UINT nFlags,const CBitmaps *pBmpUnchecked,const CBitmaps * pBmpchecked)
参数设置和CheckMenuItem类似
第三个参数是没有选中时的图片标记和第四个参数是选中时的图片标记

如何将某一项菜单变为可用
EnableMenuItem这个方法
在框架类的构造函数中m_bAutoMenuEnable=false,否则函数不能起作用

如何屏蔽一个菜单
SetMenu(NULL);
也可用之后自己去加载一个菜单
CMenu.LoadMenu


动态加载一个菜单的时候,如果定义一个局部菜单变量,在窗口重绘时将报错,应该在加载菜单后,加上,
Menu.Detach(),从而保存这个在重绘之后不销毁,,而在整个窗口销毁后再销毁


怎么样重新加载菜单
SetMenu(CMenu* pmenu )  当函数的内容为NULL时,则移除所有菜单
如果点击动态添加的菜单后,再返回关掉菜单,就会报错,则在最后加上,CMenu.Detach();

那么Detach和Atach有什么区别呢?
首先要明白C++类对象和句柄的区别,
CWnd wnd; //声明了一个CWnd对象,也就是内存中分配了一段内存,存储wnd对象;
WINDOW中把每一个窗口都用一个句柄表示;如何你要将一个CWnd对象和窗口关联起来,则就要用Atach方法进行关联;
当你需要将CWND对象和窗口卸载下来,则需要用Detach方法


命令更新机制

菜单项的状态维护,谁捕获CN_UPDATE_COMMAND_UI 消息,MFC就在其中产生一个CCmdUI对象。
我们可用手工添加ON_UPDATE_COMMAND_UI来捕获这些消息

在后台的操作:
操作系统发出WM_INITMENUPOP消息,然后由MFC的基类CFrameWnd接管。
它创建一个CCmdUI来与第一个菜单项相关联,调用对象的一个DoUpate()
而这个函数发出一个CN_UPDATE_COMMAND_UI ,这条消息带有CCmdUI对象的指针。同一个CCmdUI与第二个菜单项进行关联,这样顺序下去,直到完成所有菜单项

更新命令UI处理程序仅仅应用于弹出菜单,并不应用于永久显示的顶级菜单项目


怎么将TOOLBAR和MENU的某一项进行关联
只要将menu某一项的ID和某一菜单项设置一样均可


如何添加一个右键弹出式菜单

1》Project->add TO project->Component-》POP menu控件即可
2》 CMenu me;
 me.LoadMenu (IDR_MENU1);
 CMenu* pPopup = me.GetSubMenu(0);//弹出式菜单仅一个菜单项而已
ClientToScreen(&point);//为什么加这一项,因为>TrackPopupMenu函数弹出的坐标为屏幕坐标,所以显示位置是不多的,,应该将客户区的坐标转换为屏幕坐标,显示才是正确的  pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y,
   this);
 

一般响应菜单反应最先的是子窗口的优先权

动态添加菜单的某一项
CMenu:AppendMenu(UINT nFlags, UINT nIDNewItem = 0, LPCTSTR lpszNewItem = NULL)
     BOOL AppendMenu( UINT nFlags, UINT nIDNewItem, const CBitmap* pBmp );
    如果nFlags 被设置成MF_POPUP ,nIDNewItem, 被设置成新加菜单项的句柄
                       MF_SEPRATOR           则第二个参数将忽略
    第三个参数,新加菜单项的内容

很多类的对象都保存了自己的句柄成员变量,所以在产生一个菜单后,可在产生的对象中得到成员变量来获得对象句柄


CMenu::CreatePopupMenu
 
应用:
 CMenu sk;
 sk.CreatePopupMenu();
  GetMenu()->AppendMenu(MF_POPUP,(UINT)sk.m_hMenu,"SKD");
 sk.Detach();

如何插入一个菜单项呢?
 CMenu sk;
 sk.CreatePopupMenu();
 GetMenu()->InsertMenu(2,MF_BYPOSITION|MF_POPUP,(UINT)sk.m_hMenu,"SKD");
 sk.Detach();

给动态菜单项加响应函数

在FILEVIEW模式下选择resorce.H里添加#define IDM_HELLO                       165
然后到CFrame类中
 //{{AFX_MSG(CMainFrame)
注册消息反应的函数 afx_msg void OnHello();,
在BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
 //{{AFX_MSG_MAP(CMainFrame)
 ON_WM_CREATE()
 ON_COMMAND(IDM_TEST, OnTest)
 ON_COMMAND(IDM_HELLO,OnHello)
 //}}AFX_MSG_MAP
END_MESSAGE_MAP()
添加消息映射,这样就将响应函数和控件关联起来
产生一个菜单项ID和这个是一样的,sk.AppendMenu(MF_STRING,IDM_HELLO,"111");

框架类是不能够获取到鼠标点击事件的,,只有view类可以获取到这个时间

如何点击ENTER后,动态加载一个菜单
DrawMenuBar()函数促使菜单重绘,从而实时动态加载菜单项

CWnd::Invalidate()  如果里面的参数是true,则整个客户区域背景将全部重绘;
                    如果参数是false,则保留整个区域的背景。  参数缺省为TRUE
CWnd::OnCommand(WPARAM wParam,LPARAM lParam)
Wparam低字节标识着菜单项的ID,如果是来自加速键,则高字节是1;如果是来自控件,高字节为0;

LOWORD取data的低字节

如何在CFrame里取CVIEW类中的成员变量呢?
GetActiveView 获取当前view类的指针
BOOL CMainFrame::OnCommand(WPARAM wParam, LPARAM lParam)
{
 // TODO: Add your specialized code here and/or call the base class
 int MenuCmdID = LOWORD(wParam);
 CMenu2View *pView = (CMenu2View *)GetActiveView();
 if( MenuCmdID >= IDM_PHONE1 && MenuCmdID < IDM_PHONE1 + pView->m_strArray.GetSize() )
 {
//  MessageBox("Test");
  CClientDC dc(pView);
  dc.TextOut(0,0,pView->m_strArray.GetAt(MenuCmdID - IDM_PHONE1));
  return TRUE;
 }

 return CFrameWnd::OnCommand(wParam, lParam);
}