孙鑫VC学习笔记 6(2)

五、        右键弹出菜单

1,         Project->Add to Project->Components and Controls添加pop menu即可。

到哪一个类中?注意不要选择MainFrame中,而要加到View中!!

运行,增加了Popup菜单

程序中增加了OnContextMenu函数

You can process this message by displaying a context menu using the TrackPopupMenu.

Displays a floating pop-up menu at the specified location and tracks the selection of items on the pop-up menu.

BOOL TrackPopupMenu(
   UINT nFlags,//在鼠标右下方显示?上方显示?
   int x,
   int y,
   CWnd* pWnd,//拥有此弹出菜单的窗口
   LPCRECT lpRect = 0
lpRect

Points to a RECT structure or CRect object that contains the screen coordinates of a rectangle within which the user can click without dismissing the pop-up menu. If this parameter is 0, the pop-up menu is dismissed if the user clicks outside the pop-up menu. This must be 0 for Windows 3.0. //如果在区域菜单外点击,则弹出菜单消失
);

2,              静态添加菜单方法。

1)         在资源里编辑一个菜单

2)              View中添加WM_RBUTTONDOWN消息对应函数。

3)              在OnRButtonDown中添加如下

CMenu menu;

menu.LoadMenu(IDR_MENU1);

CMenu *pPopup=menu.GetSubMenu(0);

ClientToScreen(&point);//客户区到屏幕坐标转换,实际编程中最恨不知道这种事

pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y,GetParent());//不想在框架类显示就把GetParent()改为this。

//class wizard提示要不要为新的菜单资源增加类,不用管它

//在View和MainFrame中分别加入OnShow响应

//View show先于MainFrame show!

//去掉View show,发现MainFrame show还是不出来(因为此时在上面用的是this指针,只能由view类来响应)

//改成GetParent()以后,发现MainFrame show终于出现了

//此时再加入View show,发现又是View show出来!

//子窗口享有优先响应机会,如果子窗口没有机会,则才能交给父窗口

4)              给自己编辑的菜单加对应的处理函数(利用Classwizard)。

如果加在CMainFrame

5)              

3,              动态添加菜单(子菜单数目变化)

在MainFrame::OnCreate中试验如下

CMenu menu;

       menu.CreatePopupMenu();

GetMenu()->AppendMenu(MF_POPUP,(UINT)menu.m_hMenu,"WinSun");

//如果第一个参数是MF_POPUP,则第二个参数是句柄

//因是局部对象,注意要Detach

BOOL AppendMenu(     
    HMENU hMenu,     UINT uFlags,     UINT_PTR uIDNewItem,     LPCTSTR lpNewItem );

uFlags: MF_SEPARATOR

CMenu::CreatePopupMenu函数-->MSDN

       GetMenu()->InsertMenu(2,MF_BYPOSITION | MF_POPUP,(UINT)menu.m_hMenu,"WinSun");

BOOL InsertMenu(          HMENU hMenu,     UINT uPosition,     UINT uFlags,     PTR uIDNewItem,     LPCTSTR lpNewItem
);        menu.AppendMenu(MF_STRING,IDM_HELLO,"Hello");

       menu.AppendMenu(MF_STRING,112,"Weixin");

       menu.AppendMenu(MF_STRING,113,"Mybole");

       menu.Detach();

       响应函数添加方法:

1)  在resource.h中添加资源ID定义

#define IDM_HELLO                                  111

2)  在MainFrm.h中声明消息响应。DECLARE_MESSAGE_MAP()之前添加

afx_msg void OnHello();

3)  在MainFrm.cpp中END_MESSAGE_MAP()之前,添加

ON_COMMAND(IDM_HELLO,OnHello)

//注意不要加在默认的那一坨中间,否则系统有可能神不知鬼不觉地干掉它

4)  在MainFrm.cpp中添加CMainFrame::OnHello()函数定义

//小贴士:先添一个废的,模仿之;再删之 mock...

4,              给系统菜单添加/删除菜单项

GetMenu()->GetSubMenu(0)->AppendMenu(MF_STRING,114,"Welcome");

GetMenu()->GetSubMenu(0)->InsertMenu(ID_FILE_OPEN,

         MF_BYCOMMAND | MF_STRING,115,"维新");//在"打开"之前加入

GetMenu()->DeleteMenu(1,MF_BYPOSITION);

GetMenu()->GetSubMenu(0)->DeleteMenu(2,MF_BYPOSITION);*/

GetMenu()->DeleteMenu(       GetMenu()->GetSubMenu(1)->GetMenuItemID(0),MF_BYCOMMAND);

六、        动态添加系统菜单项

电话本程序:键盘输入人名,空格之后电话号码。回车之后,把人名添加到菜单项。当点击菜单时,显示电话本信息。

1,  给View添加private 的

CString m_strLine;//存储输入的字符串

CMenu m_menu;//菜单

int m_nIndex=-1;//用于计数,是不是第一次

2,  添加View的public成员

CStringArray m_strArray;

3,  添加View的WM_CHAR消息响应函数

4,  在View::OnChar中添加如下代码

CClientDC dc(this);

if(0x0d==nChar)

{

if(0==++m_nIndex)//如果是第一次,就创建菜单

{

m_menu.CreatePopupMenu();

GetParent()->GetMenu()->AppendMenu(MF_POPUP,

(UINT)m_menu.m_hMenu,"PhoneBook");

GetParent()->DrawMenuBar();//立即显示菜单

//这里要注意GetParent(),因View类没有menubar,会再现问题

}

       m_menu.AppendMenu(MF_STRING,IDM_PHONE1+m_nIndex,m_strLine.Left(m_strLine.Find(' ')));//Common技俩,要学会用...

//下面的技巧也比较好用...

#define IDM_PHONE1                                 201

#define IDM_PHONE2                                 202

#define IDM_PHONE3                                 203

//注意不要加在默认的那一坨中间,否则系统有可能神不知鬼不觉地干掉它

//所以要将ON_COMMAND(IDM_PHONE1, OnPhone1)等四个拿到外面来

//在里面只不过在class wizard里可以看到而已.

m_strArray.Add(m_strLine);

m_strLine.Empty();

Invalidate();//擦除先前的背景,防止重叠显示

}

else

{

m_strLine+=nChar;

dc.TextOut(0,0,m_strLine);

}

5,  添加菜单的响应函数

方法一:

1)  在Toolbar上添加一个菜单,其弹出项为ID号为IDM_PHONE1, IDM_PHONE2, IDM_PHONE3。

2)  在Rsource.h中添加

#define IDM_PHONE1                                 201

#define IDM_PHONE2                                 202

#define IDM_PHONE3                                 203

3)  利用ClassWizard给菜单项添加响应函数,并编辑函数

4)  删除菜单项(其响应函数会依然存在,并且4步中利用了ID号,可以对应过去)

方法二:

视频没有提供,但我感觉应该有其他方法。方法一太死板

//同意,确实比较傻

//就是消息映射不能"variable",比如说我从数据库读数据,再加入菜单,事先不晓得有几项,怎么办呢?

//MFC在这里就傻了...

6,  另:由框架类捕获菜单响应,而不是由View处理,可以节约代码

1)  给MainFrame添加WM_COMMAND消息响应函数, (注意是增加virtual function)

2)  在其中添加如下代码 (首先截获一下菜单栏消息) (只对动态添加的菜单项感兴趣)

int MenuCmdId=LOWORD(wParam);

The low-order word of wParam identifies the command ID of the menu item, control, or accelerator. The high-order word of wParam specifies the notification message if the message is from a control. If the message is from an accelerator, the high-order word is 1. If the message is from a menu, the high-order word is 0.

CMenu2View *pView=(CMenu2View*)GetActiveView();//要在头文件里面加

//"Menu2View"-->类名上双击,或File View

//如果不知道GetActiveView();这个函数,则应去查找CMainFrame成员函数!!这是习惯

if(MenuCmdId>=IDM_PHONE1 &&MenuCmdId<IDM_PHONE1+pView->m_strArray.GetSize())

{

CClientDC dc(pView);//牛

dc.TextOut(0,0,pView->m_strArray.GetAt(MenuCmdId-IDM_PHONE1));

//如果MenuCmdId为IDM_PHONE1,则只取0个...

//...还比较巧

return TRUE;

  }

第6点提供的方法,不能解决第5点提出方法的限制,响应菜单还是和事先编好的ID相对应,不能动态增加

OnCommand

OnCommand processes the message map for control notification and ON_COMMAND entries, and calls the appropriate member function.

思路: 如果我们在框架类中覆盖OnCommand函数,就可以截获这个函数,让其不再往下路由

RECALL:

AfxWndProc-->AfxCallWndProc-->WindowProc-->OnWndMsg-->

-->1 OnCommand

-->2 OnNotify

-->OnCmdMsg

其他注意的地方:

1,  弹出菜单(Pop-up)是不能用来作命令响应的。此项设置在菜单属性栏内。

2,  将Toolbar的ID设为菜单的ID,二者即发生了关联。

3,  在计算子菜单菜单项的索引的时候,分隔栏符也算索引。

4,  消息影射函数

Cpp文件中

BEGIN_MESSAGE_MAP(CMenu2View, CView)

//{{AFX_MSG_MAP(CMenu2View)

//位置1

//}}AFX_MSG_MAP

位置2

END_MESSAGE_MAP()

头文件中

       //{{AFX_MSG(CMenu2View)

       位置3

       //}}AFX_MSG

位置4

DECLARE_MESSAGE_MAP()

消息映射在位置1和位置2不一样,可以调用Classwizard看到修改结果

位置3和位置4的函数声明,随便放1或2都可以,没有影响

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值