Как настроить меню MFC для шаблона документа

Я инициализирую представление своего приложения MFC с помощью этой строки:

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

IDR_MAINFRAME — это идентификатор моего главного меню. Каков наилучший способ сделать это меню настраиваемым? У меня уже есть класс, производный от CMenu, который отлично справляется с контекстным меню. Разница в том, что свои контекстные меню я создаю сам, а это меню создает фреймворк.

Чтобы перезаписать главное меню, я попытался:

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

, но каким-то образом для первых элементов (которые являются всплывающими окнами) MeasureItem не запускается в экземпляре класса customMenu, в результате чего появляется крошечный квадрат, на который нужно щелкнуть, и текст разных кнопок, перекрывающих друг друга.

MENUITEM отображаются, как и ожидалось, но для каждого POPUP в подменю (а также в подпод- и подподподменю) неправильный стиль (читай: MeasureItem не вызывается). Для MENUITEMS в подменю, подподменю и подподподменю я получаю вызов MeasureItem из фреймворка.


person Jaap Scheper    schedule 05.09.2017    source источник
comment
Я думаю, что MFC динамически создает (под)меню документа. Вы можете попытаться перехватить WM_INITMENUPOPUP и сделать их пользовательскими.   -  person VuVirt    schedule 05.09.2017
comment
Из какого класса происходит ваш CMainFrame? Если это CFrameWndEx|CMDIFrameWndEx, а вы используете CMFCMenubar, скорее всего, вы не будете работать так, как хотите, поскольку обычное поведение меню переопределяется пакетом функций MFC.   -  person sergiol    schedule 05.09.2017


Ответы (1)


Спасибо за комментарий. Оказалось, что у меня была ошибка в моем производном классе CMenu. Я использовал пример кода из codeguru. Там ModifyMenu отправляет ID 0 для всплывающих меню вместо реального идентификатора всплывающих меню. void CWnd::OnMeasureItem(...) ищет меню для измерения, но ничего не находит (он ищет 0, потому что ModifyMenu сказал ему сделать это, но реальное всплывающее меню имеет какой-то другой идентификатор) и возвращает NULL. Если в вашем меню есть СЕПАРАТОР, он найдет меню для измерения, поскольку идентификатор разделителя равен 0.

Решение выглядит следующим образом:

  • Вместо отправки 0 отправьте reinterpret_cast<UINT>(menu.GetSubMenu(i)->GetSafeHmenu()) в качестве идентификатора (AFX_STATIC CMenu* AFXAPI _AfxFindPopupMenuFromID(CMenu* pMenu, UINT nID) в wincore.cpp проверяет идентификатор таким же образом).
  • Кроме того, добавьте флаг MF_POPUP.
person Jaap Scheper    schedule 06.09.2017