1.
创建动态菜单
假如ID是动态分配的,那么重载
virtual BOOLOnCmdMsg(UINT,int,void*,AFX_CMDHANDLERINFO*);
据MSDN不详细解释,当第二个参数值为CN_COMMAND时,是执行Command的消息,不过要看最后一个参数,如果最后一个参数为空,则为真正执行该命令.否则是查找是否有该命令ID的handler
BOOL TheWindow::OnCmdMsg(UINT nID,int nCode,void* pExtra,AFX_CMDHANDLERINFO* pHandlerInfo)
{
if( nCode == CN_COMMAND )
{
if( nID >= BaseMenuID && nID < MaxMenuID )
{
if( pHandlerInfo == NULL )
{
//handle the Command nID here
}
return TRUE;
}
}
return ParentWnd::OnCmdMsg(nID,nCode,pExtra,pHandlerInfo);
}
根据MSDN,菜单的ID应该是全局的(貌似应该大于0x8000), 又根据WM_COMMAND消息格式,ID最好是一个WORD,ID如果超过一个WORD,例如0x10000,那么WM_COMMAND可以收到这个菜单的命令ID(但跟MSDN的描述LOWORD不一致,而是整个DWORD,这个可能是凑巧),但是MFC的OnCmdMsg只能收到更新消息(CN_UPDATE_COMMAND_UI),不能收到执行消息.
实时设置Menu的Enable和Disable状态(MF_ENABLED,MF_DISABLED,MF_GRAYED)为何无效?比如为何不能禁用菜单项?
在查了MSDN半天之后,终于在一个code example中看到了一段不起眼的注释:
// The code fragment below shows how to disable (and gray out) the
// File\New menu item.
// NOTE: m_bAutoMenuEnable is set to FALSE in the constructor of
// CMainFrame so no ON_UPDATE_COMMAND_UI or ON_COMMAND handlers are
// needed, and CMenu::EnableMenuItem() will work as expected.
大意就是说如果设置m_bAutoMenuEnable该标志为FALSE的话,EnableMenuItem()就可以正常使用了
没有设置该标志呢?猜测framework会自动更新菜单:根据消息映射检查菜单ID是否有handler,如果有,就将其激活,否则就禁用.所以每次手动设置之后就被自动改回来了....
2.
CMDIFrameWnd为何不能处理WM_KEYDOWN消息?(MFC9) 经研究发现,接受焦点的不是他本身,而是他的Client - m_hWndMDIClient,经测试GetFocus() 的返回值的HWND与m_hWndMDIClient的值一致.
因为焦点在他的客户区m_hWndMDIClient上,不在他自己身上,所以他自己无法接受WM_KEYDOWN等等.
3.
MFC DLL注意事项: 每次从外部调用,第一次进入MFC的DLL,都需要调用 AFX_MANAGE_STATE(::AfxGetStaticModuleState());
关于AFX_MANAGE_STATE,MSDN已经说得很清楚了: Call this macro to protect an exported function in a DLL.
4.
如何在控件反射了自己的消息之后,还能让父窗口处理?答: ON_CONTROL_REFLECT_EX ,使用一个BOOL的返回值来确定是否让父窗口继续处理,TRUE表示让父窗口跳过该消息,FLASE则继续让父窗口处理.
ON_CONTROL_REFLECT 的消息处理函数返回值是void,即父窗口不能处理.但是这个消息会自动检查数据变化(如果数据没有变化,则不会调用该handler)
ON_CONTROL_REFLECT_EX 则不同,一旦控件被操作,就调用该handler,所以要手动检查数据.
ON_CONTROL_REFLECT_EX(CBN_SELCHANGE,&TheCombbox::OnSelectChange)
BOOL TheCombbox::OnSelectChange()
{
//数据真的改变?
{
处理数据,返回FALSE ,通知父窗口
}
否则
{
返回TRUE,跳过
}
}
暂时到这里.