WIN32开发时,通过资源文件定义菜单,如下:
#include "Resource.hpp"MENUPAINT MENU DISCARDABLE
BEGIN
POPUP "&File"
BEGIN
MENUITEM "&New", MENU_FILE_NEW
MENUITEM "&Open", MENU_FILE_OPEN
MENUITEM "&Save", MENU_FILE_SAVE
MENUITEM "&Save As...", MENU_FILE_SAVEAS
MENUITEM "&Exit", MENU_FILE_EXIT
END
POPUP "&Edit"
BEGIN
MENUITEM "&Undo", MENU_EDIT_UNDO
MENUITEM "&Redo", MENU_EDIT_REDO
MENUITEM "&Copy", MENU_EDIT_COPY
MENUITEM "&Cut", MENU_EDIT_CUT
MENUITEM "&Paste", MENU_EDIT_PASTE
MENUITEM "&Delete", MENU_EDIT_DELETE
END
POPUP "&Help"
BEGIN
MENUITEM "&About Paint...", MENU_HELP_ABOUT
END
END然后在程序中:
hMenu = LoadMenu(hThisInstance, TEXT("MENUPAINT"));
/* The class is registered, let's create the program*/
hwnd = CreateWindowEx (
0, /* Extended possibilites for variation */
szClassName, /* Classname */
"Paint", /* Title Text */
WS_OVERLAPPEDWINDOW, /* default window */
CW_USEDEFAULT, /* Windows decides the position */
CW_USEDEFAULT, /* where the window ends up on the screen */
544, /* The programs width */
375, /* and height in pixels */
HWND_DESKTOP, /* The window is a child-window to desktop */
hMenu, /* Use Menu */
hThisInstance, /* Program Instance handler */
NULL /* No Window Creation data */
);
这样就搞定菜单了,但问题是我想实现修改菜单资源文件后,不用重新编译程序,就可以生效,不知道如何实现,请指点一下.
#include "Resource.hpp"MENUPAINT MENU DISCARDABLE
BEGIN
POPUP "&File"
BEGIN
MENUITEM "&New", MENU_FILE_NEW
MENUITEM "&Open", MENU_FILE_OPEN
MENUITEM "&Save", MENU_FILE_SAVE
MENUITEM "&Save As...", MENU_FILE_SAVEAS
MENUITEM "&Exit", MENU_FILE_EXIT
END
POPUP "&Edit"
BEGIN
MENUITEM "&Undo", MENU_EDIT_UNDO
MENUITEM "&Redo", MENU_EDIT_REDO
MENUITEM "&Copy", MENU_EDIT_COPY
MENUITEM "&Cut", MENU_EDIT_CUT
MENUITEM "&Paste", MENU_EDIT_PASTE
MENUITEM "&Delete", MENU_EDIT_DELETE
END
POPUP "&Help"
BEGIN
MENUITEM "&About Paint...", MENU_HELP_ABOUT
END
END然后在程序中:
hMenu = LoadMenu(hThisInstance, TEXT("MENUPAINT"));
/* The class is registered, let's create the program*/
hwnd = CreateWindowEx (
0, /* Extended possibilites for variation */
szClassName, /* Classname */
"Paint", /* Title Text */
WS_OVERLAPPEDWINDOW, /* default window */
CW_USEDEFAULT, /* Windows decides the position */
CW_USEDEFAULT, /* where the window ends up on the screen */
544, /* The programs width */
375, /* and height in pixels */
HWND_DESKTOP, /* The window is a child-window to desktop */
hMenu, /* Use Menu */
hThisInstance, /* Program Instance handler */
NULL /* No Window Creation data */
);
这样就搞定菜单了,但问题是我想实现修改菜单资源文件后,不用重新编译程序,就可以生效,不知道如何实现,请指点一下.
#include <vector>
#include <map>
#include <algorithm>#define MIN_MENU_ID 8888
#define MAX_MENU_ID 9999typedef struct
{
void (*lpHandler)();
void (*lpUpdate)(CCmdUI*);
}FUNC,*LPFUNC;
typedef struct
{
CString m_strMenuName;
UINT m_dMenuID;
FUNC m_menuHandler;
}DYNAMIC_MENUINFO,*LPDYNAMIC_MENUINFO;
class CDynamicMenuManager
{
public:
CDynamicMenuManager(void);
~CDynamicMenuManager(void); void Initialize(); void AddPopupMenu(CMenu& targetMenu,std::vector<DYNAMIC_MENUINFO> rgpMenuItemInfos,CString strPopupMenuName);
void AddMenuItems(CMenu& targetMenu,std::vector<DYNAMIC_MENUINFO> rgpMenuItemInfos); void RemovePopupMenu(CMenu& fromMenu,CString strPopupMenuName);
void RemoveMenuItems(CMenu& fromMenu,std::vector<DYNAMIC_MENUINFO> rgpMenuItemInfos);
void RemoveAllAddedMenu(); void UpdateMenuItemUI(CCmdUI* pCmdUI); UINT GetValidMenuID();
static LRESULT CALLBACK newWndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam);protected:
int FindMenuInfoPosFromID(UINT uMenuID,bool bErase = false);
CMenu* GetMenuHandle(CMenu& targetMenu,CString strMenuName,int& nPos);private:
static std::map<UINT,FUNC> m_rgpHandlers;
std::map<CString,CMenu*> m_rgpPopupMenu;
std::vector<DYNAMIC_MENUINFO> m_rgpMenuItemInfos;
std::vector<UINT> m_rgpMenuID;
HWND m_hWnd;
};
#include ".\dynamicmenumanager.h"
WNDPROC oldWndProc = NULL;
std::map<UINT,FUNC> CDynamicMenuManager::m_rgpHandlers;LRESULT CALLBACK CDynamicMenuManager::newWndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
switch(uMsg)
{
case WM_COMMAND:
{
WORD nId =LOWORD(wParam) ;
if((nId >= MIN_MENU_ID) && (nId <= MAX_MENU_ID))
{
CDynamicMenuManager::m_rgpHandlers[nId].lpHandler();
}
}
break;
}
return CallWindowProc(oldWndProc,hWnd,uMsg,wParam,lParam);
}
CDynamicMenuManager::CDynamicMenuManager(void)
:m_hWnd(NULL)
{
try
{
Initialize();
m_hWnd = AfxGetMainWnd()->GetSafeHwnd();
_ASSERTE(m_hWnd);
if(m_hWnd)
oldWndProc = (WNDPROC)SetWindowLong(m_hWnd,GWL_WNDPROC,(LONG)newWndProc);
}
catch (...)
{
AfxMessageBox(_T("Error in CDynamicMenuManager::Constructor!"));
}
}CDynamicMenuManager::~CDynamicMenuManager(void)
{
if(m_hWnd)
SetWindowLong(m_hWnd,GWL_WNDPROC,(LONG)oldWndProc);
std::map<CString,CMenu*>::iterator iter = m_rgpPopupMenu.begin();
for(;iter != m_rgpPopupMenu.end();++iter)
{
delete (*iter).second;
}
m_rgpPopupMenu.clear();
m_rgpMenuID.clear();
m_rgpHandlers.clear();
m_rgpMenuItemInfos.clear();
}
void CDynamicMenuManager::Initialize()
{
m_rgpMenuID.clear();
m_rgpHandlers.clear();
m_rgpMenuItemInfos.clear();
m_rgpPopupMenu.clear();
for(UINT i = MIN_MENU_ID;i< MAX_MENU_ID;++i)
{
m_rgpMenuID.push_back(i);
}
}void CDynamicMenuManager::AddPopupMenu(CMenu& targetMenu,std::vector<DYNAMIC_MENUINFO> rgpMenuItemInfos,CString strPopupMenuName)
{
if(!(targetMenu.GetSafeHmenu() && strPopupMenuName.GetLength()) || rgpMenuItemInfos.empty())
return;
CMenu* PopupMenu = new CMenu;
PopupMenu->CreatePopupMenu(); AddMenuItems(*PopupMenu,rgpMenuItemInfos);
m_rgpPopupMenu.insert(std::make_pair(strPopupMenuName,PopupMenu));
targetMenu.AppendMenu(MF_POPUP,(UINT)(PopupMenu->m_hMenu) ,strPopupMenuName);
}
void CDynamicMenuManager::AddMenuItems(CMenu& targetMenu,std::vector<DYNAMIC_MENUINFO> rgpMenuItemInfos)
{
if(!(targetMenu.GetSafeHmenu()) || rgpMenuItemInfos.empty())
return; std::vector<DYNAMIC_MENUINFO>::iterator iter = rgpMenuItemInfos.begin();
for(;iter != rgpMenuItemInfos.end();++iter)
{
targetMenu.AppendMenu(MF_STRING,(*iter).m_dMenuID,(*iter).m_strMenuName);
m_rgpMenuItemInfos.push_back(*iter);
m_rgpHandlers.insert(std::make_pair((*iter).m_dMenuID,(*iter).m_menuHandler));
}
}void CDynamicMenuManager::RemovePopupMenu(CMenu& fromMenu,CString strPopupMenuName)
{
if(!(strPopupMenuName.GetLength() && fromMenu.GetSafeHmenu()))
return; CMenu* pMenu = NULL;
int nPos = -1;
pMenu = GetMenuHandle(fromMenu,strPopupMenuName,nPos); if(!pMenu->GetSafeHmenu())
return; for(UINT i = 0;i< pMenu->GetMenuItemCount();++i)
{
int iPos = FindMenuInfoPosFromID(pMenu->GetMenuItemID(i),true);
if(iPos != -1)
{
m_rgpHandlers.erase(pMenu->GetMenuItemID(i));
m_rgpMenuID.push_back(pMenu->GetMenuItemID(i));
}
}
if(nPos != -1)
{
fromMenu.RemoveMenu(nPos,MF_BYPOSITION);
m_rgpPopupMenu.erase(strPopupMenuName);
}
}void CDynamicMenuManager::RemoveMenuItems(CMenu& fromMenu,std::vector<DYNAMIC_MENUINFO> rgpMenuItemInfos)
{
if(!fromMenu.GetSafeHmenu() && rgpMenuItemInfos.empty())
return;
std::vector<DYNAMIC_MENUINFO>::iterator iter = rgpMenuItemInfos.begin();
for (;iter != rgpMenuItemInfos.end();++iter)
{
fromMenu.RemoveMenu((*iter).m_dMenuID,MF_BYCOMMAND);
FindMenuInfoPosFromID((*iter).m_dMenuID,true);
}
}
void CDynamicMenuManager::RemoveAllAddedMenu()
{
//Need to code!!
#pragma message(_T("Notice!!!!! RemoveAllAddedMenu func"))
}
int CDynamicMenuManager::FindMenuInfoPosFromID(UINT uMenuID,bool bErase/*=false*/)
{
if(m_rgpMenuItemInfos.empty())
return -1; std::vector<DYNAMIC_MENUINFO>::iterator iter = m_rgpMenuItemInfos.begin();
int menuItemCount = (int)m_rgpMenuItemInfos.size();
for(int i = 0;i<menuItemCount;++i)
{
if(m_rgpMenuItemInfos.at(i).m_dMenuID == uMenuID)
{
if(bErase)
{
m_rgpMenuItemInfos.erase(m_rgpMenuItemInfos.begin()+i);
m_rgpHandlers.erase(uMenuID);
}
return i;
}
}
return -1;
}
CMenu* CDynamicMenuManager::GetMenuHandle(CMenu& targetMenu,CString strMenuName,int& nPos)
{
if(!(targetMenu.GetSafeHmenu()&&strMenuName.GetLength()))
return NULL; int nMenuItemCount = targetMenu.GetMenuItemCount();
for(int i = 0;i< nMenuItemCount;++i)
{
CString str = _T("");
targetMenu.GetMenuString(i,str,MF_BYPOSITION);
if(str.CompareNoCase(strMenuName) == 0)
{
nPos = i;
return targetMenu.GetSubMenu(i);
}
}
nPos = -1;
return NULL;
}
UINT CDynamicMenuManager::GetValidMenuID()
{
if(m_rgpMenuID.empty())
return 0;
else
{
UINT menuID = m_rgpMenuID.front();
m_rgpMenuID.erase(m_rgpMenuID.begin());
return menuID;
}
}void CDynamicMenuManager::UpdateMenuItemUI(CCmdUI* pCmdUI)
{
pCmdUI->Enable();
}
// CMainFrame message handlers
void A()
{
AfxMessageBox(_T("A menu function!"));
}void B()
{
AfxMessageBox(_T("B menu function!"));
}
当时做试验,加了两个全局函数作为菜单项响应用的
//
m_menuManager = new CDynamicMenuManager;
m_menuManager->Initialize(); std::vector<DYNAMIC_MENUINFO> rgpMenuInfos;
DYNAMIC_MENUINFO menuinfo;
menuinfo.m_dMenuID = m_menuManager->GetValidMenuID();
menuinfo.m_strMenuName = _T("A");
menuinfo.m_menuHandler.lpHandler = A;
menuinfo.m_menuHandler.lpUpdate = up;
rgpMenuInfos.push_back(menuinfo); menuinfo.m_dMenuID = m_menuManager->GetValidMenuID();
menuinfo.m_strMenuName = _T("B");
menuinfo.m_menuHandler.lpHandler = B;
menuinfo.m_menuHandler.lpUpdate = up;
rgpMenuInfos.push_back(menuinfo); CMenu* pMenu = NULL;
pMenu = AfxGetMainWnd()->GetMenu()->GetSubMenu(1);
m_menuManager->AddPopupMenu(*pMenu,rgpMenuInfos,_T("Popup"));
//--------------------当然这个类还没全部写完整,不过可以用.