Howto custom-draw an MFC Menu for a DocTemplate

487 views Asked by At

I intialize the view of my MFC application with this line:

CSingleDocTemplate pDocTemplate(
   new CSingleDocTemplate(
      IDR_MAINFRAME,
      RUNTIME_CLASS(CMyDoc),
      RUNTIME_CLASS(CMainFrame),
      RUNTIME_CLASS(CMyDataView)
   )
);
AddDocTemplate(pDocTemplate);

IDR_MAINFRAME is the identifier for my mainmenu. What is the best way to make this menu custom drawn? I already have a class that derives from CMenu which does a great job for contextmenus. The difference is that I create my contextmenus myself, while this menu is created by the framework.

To overwrite the mainmenu, I tried:

customMenu.LoadMenu(IDR_MAINFRAME);
customMenu.ChangeToOwnerDraw(customMenu, *m_MenuProperties);
m_pMainWnd->SetMenu(&customMenu);

, but somehow for the first items (which are POPUPs), the MeasureItem is not fired in the customMenu class instantiation, resulting in a tiny square to click on and text of the different buttons overlapping each other.

The MENUITEMs are displayed as expected, but for every POPUP to a submenu (and to the subsub- and subsubsubmenus), the styling wrong (read: MeasureItem is not called). For MENUITEMS in sub, subsub and subsubsubmenus I receive a MeasureItem call from the framework.

1

There are 1 answers

0
Jaap Scheper On BEST ANSWER

Thanks for commenting. It turned out I had a bug in my CMenu derived class. I used a code example from codeguru. There, the ModifyMenu sends ID 0 for POPUP menus, instead of the real ID of the POPUP menus. void CWnd::OnMeasureItem(...) searches for the menu to measure, but finds nothing (it looks for 0, because ModifyMenu told him to do so, but the actual POPUP menu has some other ID) and returns NULL. If you have a SEPARATOR in your menu, it will find a menu to measure, because the separator has ID 0.

The solution is as follows:

  • Instead of sending 0, send reinterpret_cast<UINT>(menu.GetSubMenu(i)->GetSafeHmenu()) as the ID (AFX_STATIC CMenu* AFXAPI _AfxFindPopupMenuFromID(CMenu* pMenu, UINT nID) in wincore.cpp checks the same way for the ID).
  • In addition, add the flag MF_POPUP.