How do I disable and Enable Menu Items and Sub Items.

if(Selected == "drum" || Selected == "guitar" || Selected == "mic" || Selected == "computer" || Selected == "car" || Selected == "hockey" || Selected == "laptop" || Selected == "watch" )
{
      pCmdUI->Enable(Sort == 1);
}

The above code used to work before having sub menu items to that menu item. After adding sub menu items, the previous code works for sub menu items but it would not work for menu item. Can anyone please help me out with this as where am i going wrong? Thank you

Vicky

Dani AI

Generated

What changed when you added children under Manager is that Manager stopped being a command and became a popup (MF_POPUP). Popups have no command ID, so an ON_UPDATE_COMMAND_UI handler tied to the old ID will never run, and using MF_BYCOMMAND on that item will not hit it. In Win32, items that open submenus report -1 from GetMenuItemID and must be addressed by position. MFC’s menu state updates also run when WM_INITMENUPOPUP fires, and popups are treated specially in that phase. That is why ’s and ’s advice about updating the child items directly is the right fix. (learn.microsoft.com)

Pattern 1 (recommended): move all state to the submenu commands and show the current choice with radio checks. With contiguous IDs you can keep this logic in one place.

// .h
afx_msg void OnUpdateSortByManagerRange(CCmdUI* pCmdUI);
UINT m_CurrentSortCmd; // e.g., ID_SORT_BY_MANAGERNAME or ID_SORT_BY_MANAGERID

// .cpp (message map)
ON_UPDATE_COMMAND_UI_RANGE(ID_SORT_BY_MANAGERNAME, ID_SORT_BY_MANAGERID, &CDeptView::OnUpdateSortByManagerRange)

// .cpp (handler)
void CDeptView::OnUpdateSortByManagerRange(CCmdUI* pCmdUI)
{
    const bool canSort = /* your condition */;
    pCmdUI->Enable(canSort);
    pCmdUI->SetRadio(pCmdUI->m_nID == m_CurrentSortCmd);
}

MFC creates CCmdUI objects during WM_INITMENUPOPUP and calls your update handler; SetRadio is designed for exactly this use. (learn.microsoft.com)

Pattern 2 (if you really must gray the Manager popup itself): address it by position on its parent menu, then redraw.

static int FindPopupByFirstChildID(CMenu* parent, UINT firstChildID)
{
    const int n = parent->GetMenuItemCount();
    for (int i = 0; i < n; ++i)
    {
        if (CMenu* pop = parent->GetSubMenu(i))
            if (pop->GetMenuItemID(0) == firstChildID) // first child ID identifies the popup
                return i;
    }
    return -1;
}

// usage
int pos = FindPopupByFirstChildID(pSortMenu, ID_SORT_BY_MANAGERNAME);
if (pos >= 0) {
    pSortMenu->EnableMenuItem(pos, MF_BYPOSITION | MF_GRAYED);
    ::DrawMenuBar(pFrame->m_hWnd);
}

For items that open submenus you must use MF_BYPOSITION, and you must target the correct parent HMENU before calling EnableMenuItem. (learn.microsoft.com)

Tip: leave m_bAutoMenuEnable at its default and drive everything through ON_UPDATE handlers; it keeps logic centralized and predictable. (learn.microsoft.com)

Recommended Answers

All 10 Replies

I have faced this problem before....
just go to the menu right click on it ,
say add event handler, Add the ONUpdate
event handler. U will have to enable
Every menu, Sub Menu OnUpdate event handler.
Then its quite simple use the pCMdUI->enable()
method to enable / Disable menu depending upon the condition.
The other method is to create a pop up menu , where the
enabling and disabling of menus will be simpler.
Hope i have solved u r problem , if not reply back here :)

I have faced this problem before....
just go to the menu right click on it ,
say add event handler, Add the ONUpdate
event handler. U will have to enable
Every menu, Sub Menu OnUpdate event handler.
Then its quite simple use the pCMdUI->enable()
method to enable / Disable menu depending upon the condition.
The other method is to create a pop up menu , where the
enabling and disabling of menus will be simpler.
Hope i have solved u r problem , if not reply back here :)

I think I have already done that part and still it would not work. Below is the code to ensure that we are talking about the same part.

void CDeptView::OnSortManager()
{
	Selected = "MANAGER"; // Selected is a variable
       // Pulling out data from the access table
	m_pSet->m_strSort="[Managers].[ManagerName]";
	m_pSet->Requery();
	m_pSet->MoveFirst();
	UpdateData(FALSE);
}
void CDeptView::OnUpdateSortManager(CCmdUI *pCmdUI)
{
      // Setting a check to the menu item but it doesn't work now as   
         it has sub menu items
	pCmdUI->SetCheck(( m_SelectedSort == "MANAGER")? 1 : 0 );
      // Bellow is the condition when I want the menu item and its   
         sub item to be disabled.
	 if(Selected == "drum" || Selected == "guitar" || Selected == "mic" || Selected == "computer" || Selected == "car" || Selected == "hockey" || Selected == "laptop" || Selected == "watch" )
        {
      pCmdUI->Enable(Sort == 1);
        }
}

This is how I have my code and it doesn't work. In a menu bar I have Sort. Under Sort I have Manager. Under Manager I have 2 other menu items. Before having thoes 2 menu items, Manager worked with check mark as well as disabling. After having sub menu items it wont. Can anyone help me out with it.

Vicky

So what u r saying is
first the menu looked like this

SORT
|
MANAGER

Here Enabling and Disabling of manager Menu can be done,
now u have updated the manager menu like this :

SORT
|
MANAGER --- SUBMENU1
--- SUBMENU2

here u will not be able to disable the MANAGER menu as u will not be able to add an Valid event for it. Since u have added the SUNBMENU's now , u can again create the ONUPDATE event for them, then try to put the same logic into them and disable both of the sub menus. Here in the MANAGER menu when u click on it no event will be generated. MANAGER menu will be now same as SORT menu where valid event handler's cant be added. hope this helps u .

So what u r saying is
first the menu looked like this

SORT
|
MANAGER

Here Enabling and Disabling of manager Menu can be done,
now u have updated the manager menu like this :

SORT
|
MANAGER --- SUBMENU1
--- SUBMENU2

here u will not be able to disable the MANAGER menu as u will not be able to add an Valid event for it. Since u have added the SUNBMENU's now , u can again create the ONUPDATE event for them, then try to put the same logic into them and disable both of the sub menus. Here in the MANAGER menu when u click on it no event will be generated. MANAGER menu will be now same as SORT menu where valid event handler's cant be added. hope this helps u .

Yes, that is correct. But I can disable Sort. The code for that is given below.

void CDept::DisableSort(void)
{
	CWnd* pParent = GetParent(); // This is a point to the window
	 // This is a pointer to the menu on that window
        CMenu* pMenu = pParent->GetMenu();        
	
        if (m_pSet->GetRecordCount()==0) {
		MessageBox("Error", MB_ICONSTOP);
                // This disables the menu item in the 6th position which  
                    is  Sort
		pMenu->EnableMenuItem(5 , MF_BYPOSITION | MF_GRAYED );		
	}
	m_pSet->MoveFirst();
	pParent->DrawMenuBar(); // To redraw the menu
	OnSortEmployee(); // To reset the sort back to the “default condition”
}

But the question is how am i suppose to gray out or disable the menu item in the sort. Check out the code bellow

//(5) is the position of the sort, (MF_BYPOSITION ) is saying that it can be done by position of the Sort which is 5, (MF_GRAYED) means it grays out the SORT. 

pMenu->EnableMenuItem(5 , MF_BYPOSITION | MF_GRAYED );

Now the problem is I can not do the same thing for the sub menu of Sort. But I don't know the position for that. If there is another piece of code to get the job done, then I have no idea about it. This is where I am stuck.

Vicky

use the same logic for disabling the MANAGER menu also, Here u r graying it i think this shud also work for MANAGER. i will also try to write a dummy pgm and test this.

use the same logic for disabling the MANAGER menu also, Here u r graying it i think this shud also work for MANAGER. i will also try to write a dummy pgm and test this.

I tried it and it doesn't work for me. There must be a different set of code for that. First thing is I don't know the position of the Manager menu item. Second thing is I tried with the MF_BYCOMMAND (you can put IDC instead of position number) instead of MF_BYPOSITION and it still did not work. Hope to find a solution for this soon :-).

Vicky

Hope this works....

CMainFrame* pFrame ; // Memeber variable
pFrame = (CMainFrame*) AfxGetMainWnd(); 

pFrame->GetMenu()
->EnableMenuItem(ID_SORT_MANAGER,MF_GRAYED);

But make sure that u have set the m_bAutoMenuEnable = false;

Hope this works....

CMainFrame* pFrame ; // Memeber variable
pFrame = (CMainFrame*) AfxGetMainWnd(); 

pFrame->GetMenu()
->EnableMenuItem(ID_SORT_MANAGER,MF_GRAYED);

But make sure that u have set the m_bAutoMenuEnable = false;

The code that you provided here is not working. CMainFrame and pFrame is giving me errors and syntax errors too. Here is what I got right now and I still dont understand why is this not working

CWnd* pParent = GetParent();
	CMenu* pMenu = pParent->GetMenu();
	CMenu* submenu = pMenu->GetSubMenu(0);
	submenu->EnableMenuItem(0, MF_BYPOSITION | MF_GRAYED );

Please help me out :(

Wouldn't it be easiest to add 'standard' ON_UPDATE_COMMAND_UI handlers for those two sub-menus, i.e. you'd have something along the lines of:

ON_UPDATE_COMMAND_UI(IDM_SUBMENU1, OnUpdateSubmenu1)
ON_UPDATE_COMMAND_UI(IDM_SUBMENU2, OnUpdateSubmenu2)
...
void SomeClass::OnUpdateSubmenu1(CCmdUI* pCmdUI)
{
    pCmdUI->Enable( ... )
}
void SomeClass::OnUpdateSubmenu2(CCmdUI* pCmdUI)
{
    pCmdUI->Enable( ... )
}

Thanks for helping me out guys. You are both right which difference piece of code provided. It wasn't this piece of code that was not letting me accomplish the job. I finally figured out where was I making a mistake :-) I am marking this thread as solved.

Vicky

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.