Go Premium for a chance to win a PS4. Enter to Win

x
?
Solved

Adding a menu to MDI Chile Window

Posted on 2004-08-26
14
Medium Priority
?
510 Views
Last Modified: 2013-11-20
Hello,
 
I am developing an MDI application in VC++. I need to create an  MDI child menu attached to the Child Window without replacing the mainframe's menu. To be more specific my MDI Child window is using CFormView. I should be able to access both the child window menu and the main frame menu both simultaneously from the window at a time. Can you please suggest any solution to this.Please email to me if you have any useful relevant information on the above.
 
Thanks
Madhavi
0
Comment
Question by:osi-sys
  • 7
  • 5
  • 2
14 Comments
 
LVL 31

Expert Comment

by:Zoppo
ID: 11901175
Hi osi-sys,

well, IMO a MDI frame window can only have one menu at a time ... by default you have at least two menu resources, one
called IDM_MAINFRAME which is the menu which is shown when no MDI child frame is open and one for each view
class, i.e. IDM_MY_TYPE for CMyView ... so what you can do is simply adding the menus/menu items from IDM_MAINFRAME
you need to have with open child frame to the child frame's menu.

hope that helps,

ZOPPO
0
 

Author Comment

by:osi-sys
ID: 11901464
Hello ZOPPO,

Thanks for the inputs.

But I am unable to get you----"so what you can do is simply adding the menus/menu items from IDM_MAINFRAME
you need to have with open child frame to the child frame's menu" ---- Can you please explain more on your comment.

My requirement is I should be able to access CMYView menu(IDM_MY_TYPE ) fram CMYView window's menu bar and CMainFrame menu( IDM_MAINFRAME ) from the CMainFrame menu bar. I do not want the mainframe menu to be replaced with CMyview's menu when child window is shown. Hope you got what I am trying to say.

Can you please suggest a solution to my problem.
Thanks in anticipation of information.
0
 
LVL 31

Expert Comment

by:Zoppo
ID: 11902098
well, ok, that's quite difficult ... in Windows it's not possible that a child window has a menu!

I managed after a while to do it like you want, but there are some more steps to do:
(In following I assume the AppWizard created class are CMyApp, CMyView, CMyDoc, CMainFrame, CChildFrame a.s.o.)

1. In CMyApp::InitInstance() search the lines
>      CMultiDocTemplate* pDocTemplate;
>      pDocTemplate = new CMultiDocTemplate(
>            IDR_MYTYPE,
>            RUNTIME_CLASS(CMyDoc),
>            RUNTIME_CLASS(CChildFrame), // custom MDI child frame
>            RUNTIME_CLASS(CMyView));
and replace the 'IDR_MYTYPE' with 'IDR_MAINFRAME' ... this will ensure the child frame uses the same main menu as the main frame
>      CMultiDocTemplate* pDocTemplate;
>      pDocTemplate = new CMultiDocTemplate(
>            IDR_MAINFRAME,
>            RUNTIME_CLASS(CMyDoc),
>            RUNTIME_CLASS(CChildFrame), // custom MDI child frame
>            RUNTIME_CLASS(CMyView));

2. Create a new dialog resource without caption, border and with style 'Popup'
3. Create a new CDialog-derived class (i.e. CMyMenuBar) with the resource ID of the new dialog resource from 2.
4. In MyView.h iadd lines like this:
>            class CMyMenuBar; // forward declaration
>            
>            class CMyView : public CFormView
>            {
>              CMyMenuBar* m_pWndMenuBar;
>            public:
>              void      UpdateMenuBarPos();
>             ...
>            };
5. In constructor CMyView::CMyView() set m_pWndMenuBar = NULL;
6. Add a 'WM_CREATE' and a 'WM_DESTROY' message handler via ClassWizard in CMyView
7. In MyView.cpp implement the CMyView::UpdateMenuBarPos, CMyView::OnCreate and CMyView::OnDestroy like this:
>            #include "MyMenuBar.h"
>
>            int CMyView::OnCreate(LPCREATESTRUCT lpCreateStruct)
>            {
>                  if (CFormView::OnCreate(lpCreateStruct) == -1)
>                        return -1;
>
>                  m_pWndMenuBar = new CMyMenuBar;
>                  m_pWndMenuBar->Create( CMyMenuBar::IDD, GetParent() );
>                  m_pWndMenuBar->ShowWindow( SW_SHOW );
>
>                  m_pWndMenuBar->SetParent( GetParent() );
>
>                  return 0;
>            }
>
>            void
>            CMyView::UpdateMenuBarPos()
>            {
>                  if ( NULL == m_pWndMenuBar )
>                        return;
>
>                  CRect rect;
>                  GetParent()->GetClientRect( &rect );
>
>                  int iTmp = rect.bottom;
>                  rect.bottom = rect.top + min( rect.Height(), GetSystemMetrics( SM_CYMENU ) );
>
>                  m_pWndMenuBar->MoveWindow( &rect );
>
>                  rect.top = rect.bottom;
>                  rect.bottom = iTmp;
>
>                  MoveWindow( &rect );
>            }
>
>            void CMyView::OnDestroy()
>            {
>                  m_pWndMenuBar->DestroyWindow();
>                  delete m_pWndMenuBar;
>                  m_pWndMenuBar = NULL;
>
>                  CFormView::OnDestroy();
>            }
8. In childfrm.cpp implement a new function UpdateViewMenuBar like this:
>            #include "FormMenuDoc.h"
>            #include "FormMenuView.h"
>            
>            void CChildFrame::UpdateViewMenuBar()
>            {
>                  CView* pView = GetActiveView();
>
>                  if ( NULL == pView || FALSE == pView->IsKindOf( RUNTIME_CLASS( CMyView ) ) )
>                        return;
>
>                  ((CMyView*)GetActiveView())->UpdateMenuBarPos();      
>            }
9. Add via ClassWizard message handlers for 'WM_SIZE' and 'WM_MOVING' in CChildFrame and implement them like this:
>            void CChildFrame::OnMoving(UINT fwSide, LPRECT pRect)
>            {
>                  CMDIChildWnd::OnMoving(fwSide, pRect);
>
>                  UpdateViewMenuBar();
>            }
>
>            void CChildFrame::OnSize(UINT nType, int cx, int cy)
>            {
>                  CMDIChildWnd::OnSize(nType, cx, cy);
>                  
>                  UpdateViewMenuBar();
>            }


That's it (hopefully, if I didn't forget something) ... works fine in my testapp ... if you have problems implementing it please post me
a email address where I can send you my test app.


Hope that helps,

ZOPPO
0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
LVL 31

Expert Comment

by:Zoppo
ID: 11902170
ahh ... sorry, indeed I forgot something:

In the dialog resource you should create from point 2. you'll have to assign the menu resource 'IDR_MYTYPE' in the dialog properties
in 'General' -> 'Menu'

ZOPPO
0
 
LVL 31

Expert Comment

by:Zoppo
ID: 11902303
and, one more thing:

MFC has a bug in handling WM_UPDATE_COMMAND_UI messages in dialogs ... this leads to behavior
that a menu item, which is disabled by a OnUpdateCommandUI-handler won't be shown as disabled
allthough it won't be executed when clicked.

To workaround this simply add a function
      void HandleMenuUpdate(CMenu* pMenu, BOOL bSysMenu);
to CMyMenuBar class and message handlers for 'WM_INIT_MENU' and 'WM_INIT_MENU_POPUP'
and implement these three functions like this:

>            void CMyMenuBar::OnInitMenu(CMenu* pMenu)
>            {
>                  CDialog::OnInitMenu(pMenu);
>                  
>                  HandleMenuUpdate( pMenu, FALSE );
>            }
>
>            void CMyMenuBar::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu)
>            {
>                  CDialog::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu);
>
>                  HandleMenuUpdate( pPopupMenu, bSysMenu );
>            }
>
>            void CMyMenuBar::HandleMenuUpdate(CMenu* pMenu, BOOL bSysMenu)
>            {
>                  if (bSysMenu)
>                        return;     // don't support system menu
>                  
>                  ASSERT(pMenu != NULL);
>                  // check the enabled state of various menu items
>                  
>                  CCmdUI state;
>                  state.m_pMenu = pMenu;
>                  ASSERT(state.m_pOther == NULL);
>                  ASSERT(state.m_pParentMenu == NULL);
>                  
>                  // determine if menu is popup in top-level menu and set m_pOther to
>                  //  it if so (m_pParentMenu == NULL indicates that it is secondary popup)
>                  HMENU hParentMenu;
>                  if (AfxGetThreadState()->m_hTrackingMenu == pMenu->m_hMenu)
>                        state.m_pParentMenu = pMenu;    // parent == child for tracking popup
>                  else if ((hParentMenu = ::GetMenu(m_hWnd)) != NULL)
>                  {
>                        CWnd* pParent = GetTopLevelParent();
>                        // child windows don't have menus -- need to go to the top!
>                        if (pParent != NULL && (hParentMenu = ::GetMenu(pParent->m_hWnd)) != NULL)
>                        {
>                              int nIndexMax = ::GetMenuItemCount(hParentMenu);
>                              for (int nIndex = 0; nIndex < nIndexMax; nIndex++)
>                              {
>                                    if (::GetSubMenu(hParentMenu, nIndex) == pMenu->m_hMenu)
>                                    {
>                                          // when popup is found, m_pParentMenu is containing menu
>                                          state.m_pParentMenu = CMenu::FromHandle(hParentMenu);
>                                          break;
>                                    }
>                              }
>                        }
>                  }
>                  
>                  state.m_nIndexMax = pMenu->GetMenuItemCount();
>                  for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax; state.m_nIndex++)
>                  {
>                        state.m_nID = pMenu->GetMenuItemID(state.m_nIndex);
>                        if (state.m_nID == 0)
>                              continue; // menu separator or invalid cmd - ignore it
>                        
>                        ASSERT(state.m_pOther == NULL);
>                        ASSERT(state.m_pMenu != NULL);
>                        if (state.m_nID == (UINT)-1)
>                        {
>                              // possibly a popup menu, route to first item of that popup
>                              state.m_pSubMenu = pMenu->GetSubMenu(state.m_nIndex);
>                              if (state.m_pSubMenu == NULL || (state.m_nID = state.m_pSubMenu->GetMenuItemID(0)) == 0 || state.m_nID == (UINT)-1)
>                              {
>                                    continue;       // first item of popup can't be routed to
>                              }
>                              state.DoUpdate(this, FALSE);    // popups are never auto disabled
>                        }
>                        else
>                        {
>                              // normal menu item
>                              // Auto enable/disable if frame window has 'm_bAutoMenuEnable'
>                              //    set and command is _not_ a system command.
>                              state.m_pSubMenu = NULL;
>                              state.DoUpdate(this, state.m_nID < 0xF000);
>                        }
>                        
>                        // adjust for menu deletions and additions
>                        UINT nCount = pMenu->GetMenuItemCount();
>                        if (nCount < state.m_nIndexMax)
>                        {
>                              state.m_nIndex -= (state.m_nIndexMax - nCount);
>                              while (state.m_nIndex < nCount && pMenu->GetMenuItemID(state.m_nIndex) == state.m_nID)
>                              {
>                                    state.m_nIndex++;
>                              }
>                        }
>                        state.m_nIndexMax = nCount;
>                  }
>            }


ZOPPO
0
 
LVL 6

Expert Comment

by:nabehs
ID: 11903712
Why not just try:

HMENU hmenu = ::LoadMenu(AfxGetInstanceHandle( ), MAKEINTRESOURCE(IDR_MYMENU));

::SetMenu(myview.m_hWnd, hmenu);

Just wondering why this should not work.

0
 
LVL 31

Expert Comment

by:Zoppo
ID: 11910514
Hi nabehs,

have you tried it?

I did, and SetMenu() returns FALSE and GetLastError() returns 1436 which is
ERROR_CHILD_WINDOW_MENU which is described in MSDN with comment
'Child windows cannot have menus.'!

ZOPPO
0
 
LVL 6

Expert Comment

by:nabehs
ID: 11910531
then that means there is no way to put a menu on a child view, because in any way you try it will end up calling SetMenu
0
 
LVL 31

Expert Comment

by:Zoppo
ID: 11910694
yes, exactly ... therefor I developed a workaround using a modeless popup dialog (so no WS_CHILD style) and
fit it into the child frame as if it was a menu bar ... it's the only way I found to do what osi-sys wants to have ...
0
 

Author Comment

by:osi-sys
ID: 11938637
Hello Zoppo

Many Thanks for all your inputs and help.
Can you please post me the test application that you have developed. This will help me to easily understand the solution given by you. My email id is: jmadhavi@yahoo.com.

Thanks once again.
Madhavi.
0
 

Author Comment

by:osi-sys
ID: 11938652
Hello Zoppo

Many Thanks for all your inputs and help.
Can you please post me the test application that you have developed. This will help me to easily understand the solution given by you. My email id is: jmadhavi@yahoo.com.

Thanks once again.
Madhavi (osi-sys).


0
 

Author Comment

by:osi-sys
ID: 12082274
Hello Zoppo,

I am Madhavi, Hope you remember me. You had helped me in adding a menu to Form view and you had also sent me a test application. I have one problem in and I'm unable to solve. Tyr clicking on minimise and maximize button of Form view, the view is not getting minimized and maximized. If I comment out OnSize and OnMoving part of the code, it's working fine. Can you please help me to solve this problem.

Thanks
Madhavi
0
 
LVL 31

Accepted Solution

by:
Zoppo earned 500 total points
ID: 12083194
Hi Madhavi,


well, it's a little bit strange ... I'm not exaclty sure what the reason is and why it sometimes seems to work ... I suspect the problem is that some messages sent by the system are handled by the overlapped menubar dialog instead, as wanted, by the main frame ...

The workaround I found was to set the WS_EX_TOOLWINDOW style to the menubar dialog.

To do this simply open the dialog resource and check the 'Tool window' in the 'Extended styles' tab of the dialogs properties dialog.


I hope that helps,

ZOPPO
0
 

Author Comment

by:osi-sys
ID: 12100723
Hello Zoppo,

Thanks for your help.. One more query...
Since dialog is attached to form view, the menu appears to be disabled i.e grayed. It appears to be enabled only when clicked on it.  Is there option to make the menu attached to the view  appear enabled always irrespective of the focus. Can you please suggest any solution to this?

Thanks
Madhavi.
0

Featured Post

Vote for the Most Valuable Expert

It’s time to recognize experts that go above and beyond with helpful solutions and engagement on site. Choose from the top experts in the Hall of Fame or on the right rail of your favorite topic page. Look for the blue “Nominate” button on their profile to vote.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction: Finishing the grid – keyboard support for arrow keys to manoeuvre, entering the numbers.  The PreTranslateMessage function is to be used to intercept and respond to keyboard events. Continuing from the fourth article about sudoku. …
In this post we will learn different types of Android Layout and some basics of an Android App.
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
How to fix incompatible JVM issue while installing Eclipse While installing Eclipse in windows, got one error like above and unable to proceed with the installation. This video describes how to successfully install Eclipse. How to solve incompa…

971 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question