Solved

OnInitMenuPopup

Posted on 2010-09-16
7
1,047 Views
Last Modified: 2013-11-20
Hi Experts,

I am trying to use OnInitMenuPopup to dynamically modify my mainframe menus (File, Edit, etc) based on user settings in my application.  However, I'm having a problem with DeleteMenu.  It seems like once I remove a menu item using this command it is permanently gone - it doesn't show up the next time OnInitMenuPopup is called for that menu.  I'd like to have my default menu as the starting point each time OnInitMenuPopup is called and then adjust the settings based on the current settings.  Is there a good way to do this?

Thanks,
Kevin
0
Comment
Question by:kjc1111
  • 4
  • 2
7 Comments
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 33692426
>> It seems like once I remove a menu item using this command it is permanently gone

That is what the DeleteMenu does - it deletes the menu item.  But why should it be a problem, either the user can use that item or they can't so why should you need to keep deleting it.


If the user can somehow change during the running of the app then you could try just disabling the menu item instead.
0
 

Author Comment

by:kjc1111
ID: 33692532
Hi Andy,

It is an MDI editing program and there are a lot of menu items available in the app that won't necessariliy be required for each type of file they are editing.  I want to provide a way for the user to customize the functionality for the current file and remove items they don't currently need.  This can even vary from file to file.  I know I can just disable unneeded items but my preference would be to remove them, if possible.  Kind of like toolbars - some apps allow you to dynamically show them or hide them, and if you decide to hide them you can still change your settings to get them back.

Thanks,
Kevin
0
 
LVL 30

Expert Comment

by:Zoppo
ID: 33693163
Hi kjc1111,

IMO there's no generic way to do what you want, at least not in 'old' MFC - is it an option for you to use 'new' MFC (either with VS 2010 or from MFC FeaturePack for VS 2008) using a CMFCMenuBar in your mainframe?

If so I could post you some code how this could work ...

ZOPPO
0
Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

 

Author Comment

by:kjc1111
ID: 33693273
Hi Zoppo,

I'm stuck with VC6 since I'm using Stingray Studio as well, and it costs too much to upgrade Stingray so it will support later versions of VS.

Thanks,
Kevin

0
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 33693341
The only thing I can think of is when your app start you build up some collections of what the current menu's are  (maybe as CMenu objects themselves?).  Then in the OnInitMenuPopup code you have you remove as at present or add if required.

0
 

Author Comment

by:kjc1111
ID: 33694319
I noticed that when OnInitMenuPopup is called the nIndex value is always 0 for my mainframe menus.  Is that normal or am I missing a setting somewhere?  If it's normal, is there a way to determine which menu is active, or do I have to do something like check the labels of the menu items for a match to a known value?

Thanks,
Kevin
0
 

Accepted Solution

by:
kjc1111 earned 0 total points
ID: 33697108
Hi Andy and Zoppo,

I was kicking around the idea of setting up some template menus as Andy suggested, and both your responses led me to believe I'd have to implement some custom stuff myself, which I did.  The code is below for anyone who's interested.  It works for both mainframe menus and context menus.  I just finished coding it so there might still be some bugs, but it seems to work so far.

Regards,
Kevin


CMainFrame.h:



	// Protected functions.



	void BuildMenu( CMenu* pOriginal, CMenu* pNew );

	void CustomizeMenu( CMenu* pMenu );

	void DeleteSubMenus();

	void PopulateMRUList( CMenu* pMenu );



	// Message handlers.



	afx_msg void OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu);



	// This variable contains the default menu settings.



	CMenu* m_pDefaultMenu;



	// This list contains our working pop-up menus.



	CList< CMenu*, CMenu* > m_listSubMenus;





CMainFrame.cpp



	// Message map.



	ON_WM_INITMENUPOPUP()







int

CMainFrame::OnCreate

(

	LPCREATESTRUCT lpCreateStruct

)

{



	...



	// Create the default menu.



	m_pDefaultMenu = new CMenu();

	m_pDefaultMenu->LoadMenu( IDM_MY_MENU );



	DeleteSubMenus();



	...



}





CMainFrame::~CMainFrame

(

	void

)

{



	...



	// Delete menus.



	if ( m_pDefaultMenu != NULL )

	{

		delete m_pDefaultMenu;

	}



	DeleteSubMenus();



	...



}





void 

CMainFrame::DeleteSubMenus

( 

	void 

) 

{ 



	POSITION pos = m_listSubMenus.GetHeadPosition();



	while ( pos != NULL )

	{

		CMenu* pMenu = m_listSubMenus.GetNext( pos );

		delete pMenu;

	}



	m_listSubMenus.RemoveAll();



} 





void 

CMainFrame::OnInitMenuPopup

(

	CMenu* pPopupMenu, 

	UINT nIndex, 

	BOOL bSysMenu 

)

{



	// Make sure we have menu items to work with.



	if ( pPopupMenu->GetMenuItemCount() == 0 )

	{

		SECWorkbook::OnInitMenuPopup( pPopupMenu, nIndex, bSysMenu );

		return;

	}



	// If this is a sub-menu then it will have been customized when

	// the top-level menu was handled earlier.



	if ( nIndex > 0 )

	{

		SECWorkbook::OnInitMenuPopup( pPopupMenu, nIndex, bSysMenu );

		return;

	}



	// Get the appropriate sub-menu index for our default menu.

	// This code assumes that the first item in each top-level 

	// menu will never be changed.



	CString strKey;

	pPopupMenu->GetMenuString( 0, strKey, MF_BYPOSITION );



	CMenu* pTemplate = NULL;

	int nCount = m_pDefaultMenu->GetMenuItemCount();



	for ( int nSubItem = 0; nSubItem < nCount; nSubItem++ )

	{

		CMenu* pTest = m_pDefaultMenu->GetSubMenu( nSubItem );



		CString strTest;

		pTest->GetMenuString( 0, strTest, MF_BYPOSITION );



		if ( strTest == strKey )

		{

			pTemplate = pTest;

			break;

		}

	}



	// If we couldn't find the sub-menu then this is a context menu.

	// These are dynamically created from the master context menu.

	// We can skip right to the customization since any modifications 

	// we make won't affect future calls.  Otherwise we need to 

	// create a copy of the template so it doesn't get permanently

	// changed.



	if ( pTemplate != NULL )

	{

		// Clear the current set of menu items.



		while ( pPopupMenu->GetMenuItemCount() > 0 )

		{

			pPopupMenu->DeleteMenu( 0, MF_BYPOSITION );

		}



		// Clear any working sub-menus from the previous call.



		DeleteSubMenus();



		// Recursively re-build the menu list using our master list.



		BuildMenu( pTemplate, pPopupMenu );

	}



	// Recursively customize the menu.



	CustomizeMenu( pPopupMenu );



}





void 

CMainFrame::BuildMenu

( 

	CMenu* pOriginal,

	CMenu* pNew

) 

{ 



	CString strText;



	// Loop through all menu items in the original.



	for ( int nIndex = 0; nIndex < pOriginal->GetMenuItemCount(); nIndex++ )

	{

		pOriginal->GetMenuString( nIndex, strText, MF_BYPOSITION );

		UINT nId = pOriginal->GetMenuItemID( nIndex );



		// Handle separators.



		if ( nId == 0 )

		{

			pNew->AppendMenu( MF_SEPARATOR );

		}



		// MRU files are a special case.



		else if ( nId == ID_FILE_MRU_FILE1 )

		{

			PopulateMRUList( pNew );

		}



		// Handle sub-menus.



		else if ( nId == ( UINT )-1 )

		{

			CMenu* pOriginalSubMenu = pOriginal->GetSubMenu( nIndex );



			// Create the sub-menu.



			CMenu* pNewSubMenu = new CMenu();

			pNewSubMenu->CreatePopupMenu();

			m_listSubMenus.AddTail( pNewSubMenu );



			// Recursively populate the sub-menu.



			BuildMenu( pOriginalSubMenu, pNewSubMenu );



			// Add the pop-up text.



			HMENU hMenu = pNewSubMenu->m_hMenu;

			pNew->AppendMenu( MF_POPUP, ( UINT )hMenu, strText );

		}



		// This is a normal menu item.



		else

		{

			pNew->AppendMenu( MF_STRING, nId, strText );

		}

	}



}  





void 

CMainFrame::CustomizeMenu

( 

	CMenu* pMenu

) 

{ 



	// Loop through and recursively customize sub-menus.



	for ( int nIndex = 0; nIndex < pMenu->GetMenuItemCount(); nIndex++ )

	{

		UINT nId = pMenu->GetMenuItemID( nIndex );



		if ( nId == ( UINT )-1 )

		{

			CMenu* pSubMenu = pMenu->GetSubMenu( nIndex );

			CustomizeMenu( pSubMenu );

		}

	}



	// Customize the menu.



	m_pMyCustomizeClass->Customize( pMenu );



} 

 



void 

CMainFrame::PopulateMRUList

( 

	CMenu* pMenu

) 

{ 



	// Get the MRU list.



	CRecentFileList* pRecent = GetApp()->GetRecentFileList();



	// Check if we have any valid files.



	if ( pRecent->m_arrNames[ 0 ].IsEmpty() )

	{

		CString strText = _T( "No Recent Files" );

		pMenu->AppendMenu( ( MF_STRING | MF_GRAYED ), 0, strText );

		return;

	}



	// Add all valid files.



	TCHAR szCurDir[ _MAX_PATH ];

	GetCurrentDirectory( _MAX_PATH, szCurDir );

	int nCurDir = lstrlen( szCurDir );



	for ( int nFile = 0; nFile < pRecent->GetSize(); nFile++ )

	{

		int nMRU = ID_FILE_MRU_FILE1 + nFile;

		CString strText = pRecent->m_arrNames[ nFile ];

		

		if ( strText.IsEmpty() )

		{

			return;

		}



		pRecent->GetDisplayName( strText, nFile, szCurDir, nCurDir );

		pMenu->AppendMenu( MF_STRING, nMRU, strText );

	}



} 

 



bool

MyCustomizeClass::Customize

( 

	CMenu* pMenu

) 

{ 

	

	// Do whatever you like to the menu in here.



}

Open in new window

0

Featured Post

What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

Suggested Solutions

Introduction: Dynamic window placements and drawing on a form, simple usage of windows registry as a storage place for information. Continuing from the first article about sudoku.  There we have designed the application and put a lot of user int…
Introduction: Dialogs (1) modal - maintaining the database. Continuing from the ninth article about sudoku.   You might have heard of modal and modeless dialogs.  Here with this Sudoku application will we use one of each type: a modal dialog …
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.
Polish reports in Access so they look terrific. Take yourself to another level. Equations, Back Color, Alternate Back Color. Write easy VBA Code. Tighten space to use less pages. Launch report from a menu, considering criteria only when it is filled…

706 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

Need Help in Real-Time?

Connect with top rated Experts

18 Experts available now in Live!

Get 1:1 Help Now