How to show/hide a Toolbar (the ENTIRE bar, not an individual button) dynamically in MFC? - mfc

I created an SDI app with a single menu and a single toolbar in MFC:
I am supposed to show/hide the toolbar dynamically via this code:
...
m_wndToolBar.ShowWindow(SW_HIDE);
...
It did visually hide the toolbar but left a blank, seemingly still working space in the dock region that blocks the main view repositioning. And, when I try to drag the menu, it can dock to the top and bottom line just like the toolbar is there.
I must have missed some necessary steps. So how can I "really" remove the toolbar and raise the main view close to the menu?

Assuming you are using a (relatively) recent version of MFC, and that your m_wndToolBar member is a CMFCToolBar (or derived therefrom), then you should use the ShowPane() member function, rather than the more general ShowWindow() member. Using the former allows the Framework to make the required adjustments to the docking system.
From the linked document:
Call this method instead of the CWnd::ShowWindow when showing or
hiding dockable panes.
(Note that a CMFCToolBar is derived from CPane via the CMFCBaseToolBar class.)
In your call to ShowPane(), the first argument will be TRUE to show the toolbar or FALSE to hide it; the other two arguments will most likely be FALSE, as you want to readjust the docking layout immediately and you generally don't want to activate a toolbar.
So:
//...
m_wndToolBar.ShowPane(FALSE, FALSE, FALSE); // Hide toolbar
//...
Or:
//...
m_wndToolBar.ShowPane(TRUE, FALSE, FALSE); // Show toolbar
//...
Note also that ShowPane() (or, rather, a version of it) is called by the Framework's default handler for a show/hide menu item with the ID of any toolbar (which toggles its visibility); from "afxframewndex.cpp":
BOOL CFrameWndEx::OnPaneCheck(UINT nID)
{
ASSERT_VALID(this);
CBasePane* pBar = GetPane(nID);
if (pBar != NULL)
{
ShowPane(pBar, (pBar->GetStyle() & WS_VISIBLE) == 0, FALSE, FALSE);
return TRUE;
}
return FALSE;
}

Related

MFC How do you determine if ON_UPDATE_COMMAND_UI is for the menubar or toolbar?

I have a case where I want the menus to set the check on items using ON_UPDATE_COMMAND_UI; however, on the toolbar I'm going to use a dropdown toolbar, so I only want to select the correct toolbar item and not change its checked state.
How do I determine if the ON_UPDATE_COMMAND_UI call is for the menu-bar or the toolbar?
You can check the m_pMenu member of the handler's given CCmdUI parameter; if the routine was invoked for a menu item, that will be a valid CMenu* pointer; if not, it will be NULL:
void CMyClass::OnUpdateHandler(CCmdUI *pCmdUI)
{
if (!pCmdUI->m_pMenu) {
// NOT for a menu
}
else {
// For a menu
}
}

How to manually show CMFCToolBarComboBoxButton sub-menu?

Standard behaviour for CMFCToolBarComboBoxButton is to have a clickable button plus a drop-down arrow for displaying a submenu. I want to show the submenu independently of where the click was made. How can I do it?
My code to create the button is, more or less, the following (it has been extracted from a larger project, so I apologize for any missing not-too-important piece of code):
// In class declaration:
CMenu m_menu;
CMFCToolBar m_toolbar;
// Where toolbar initialization takes place:
m_menu.CreateMenu();
// ... populate menu
// ID_BUTTON is the ID in the resource file for the toolbar button, 0 is the index for the button icon
CMFCToolBarMenuButton button(ID_BUTTON, m_menu.GetSafeHmenu(), 0);
m_toolbar.ReplaceButton(ID_BUTTON, button);
I've been looking around for awhile and cannot find a related answer.
The solution happened to be very straightforward, just call the OnClick function of the CMFCToolBarComboBoxButton button from its associated ON_COMMAND.
// ... message map
ON_COMMAND(ID_BUTTON, OnToolbarMenuButtonClicked)
// ...
void MyWnd::OnToolbarMenuButtonClicked()
{
const int index = m_toolbar.CommandToIndex(ID_BUTTON);
auto button = (CMFCToolBarComboBoxButton*)m_toolbar.GetButton(index);
button->OnClick(NULL, TRUE);
}
This behaviour is not documented and, contrary to what common sense told me, it doesn't create an infinite recursive call. It seems that the "main" button is still controlled by CMFCToolBarButton, while just the "arrow-button" is controlled by the CMFCToolBarComboBoxButton.
PS: obviously, and out of the scope of the question, the OnToolbarMenuButtonClicked can be used for a very different purpose, such as the default action while the sub-menu contains other less-frequent options.

How to hide CMFCToolBar from customize dialog Toolbar property page?

I am working on Mfc application that contains ribbon and some toolbars. I made a CMFCToolBar dummy object to store all the icons from ribbon tabs and use it later.
I have hidden the dummy toolbar from the UI. but couldn't hide from customize dialog Toolbar Property Page.
Image(untitled bar is the dummy toolbar)
I dont want the user to see the dummy toolbar in the property page. For this I have also made CMFCToolBarsCustomizeDialog extension and inherited the ShowToolBar Function but it is not working.
Code:
void ShowToolBar(CMFCToolBar* pToolBar, BOOL bShow)
{
this->m_pToolbarsPage->ShowToolBar(pToolBar, bShow);
}
Simply override CMFCToolBar::AllowShowOnList and return FALSE.
BOOL CMyToolBar::AllowShowOnList() const
{
return FALSE;
}

Disable some context menu items if no items are checked

I have a tree view (CTreeView) that will show me a pop-up menu after I right-click my mouse on it.
In my context menu there are only 3 items (i.e A, B, C) for selection and my tree view displays a long list of ordered foods designed with check-boxes. I would like to disable menu items A and B if no ordered foods are checked and enable them when any is.
I create CFoodView::OnUpdateItemA(CCmdUI* pCmdUI) //CFoodView inherits CTreeView
and CFoodView::OnUpdateItemB(CCmdUI* pCmdUI) to handle their states like so
CFoodView::OnUpdateItemB(CCmdUI* pCmdUI)
{
if TreeView has no items
{
pCmdUI->Enable(FALSE);
}
else
{
*Search* the tree to get selected items
if None is checked
{
pCmdUI->Enable(FALSE);
}
else there are checked items
pCmdUI->Enable(TRUE);
}
}
Method CFoodView::OnUpdateItemA(CCmdUI* pCmdUI) is the same.
I think this isn't a correct way to handle this GUI feature.
Well, you did not submit all important information. How did you create menu item handlers?
Assuming you insert handlers the proper way, still did not provide any information how you are invoking popup menu.
If all you did was properly done it is the proper way of handling update menu.
The most common mistake is designating view itself as the window that handles popup updates and commands. In order to use MFC menu update mechanism, you have to pass a pointer to the main window not to the tree view:
CWnd *pMainWnd = AfxGetMainWnd();
ASSERT(pMainWnd != nullptr);
pSubMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, pMainWnd);
If this will not work reexamine the way you create handler and/or the place you invoke the TrackPopupMenu function.

How can I disable and gray the top level menu item using MFC

I have a dialog application in which I want to have clickable menu items at the top of the dialog. These items do not show a drop down menu but actually run the associated commands.
I did this by setting Popup=False in the dialogs properties and assigning a message-id but my problem is not having the ability to disable the item properly when it makes no sense for the item to be clickable (depending on internal state stored in the dialog)
I have already found out how to disable any popup-parent menu items from http://www.microsoft.com/msj/0299/c/c0299.aspx, but this isn't exactly what I want
I have also found out how to add menu command routing to dialogs from the msdn knowledgebase article KB242577.
This works fine for sub-menu items, but not for the top level menu.
I am currently using the following function to do the disabling
void CYourDlg::EnableMenuItem(UINT nCommand, BOOL bEnable)
{
CMenu* pMenu = GetMenu();
pMenu->EnableMenuItem(nCommand, bEnable ? 0 : MF_DISABLED | MF_GRAYED);
}
This half works, if you alt-tab away from the app it does show as disabled, otherwise it doesn't.
Is there a way to invalidate the area programmatically?
I think an non-client area message may be involved.
I have not tried but in regular window (not dialog) CWnd::DrawMenuBar should do what you want. It might work with dialog based applications as well.
void CYourDlg::EnableMenuItem(UINT nCommand, BOOL bEnable)
{
CMenu* pMenu = GetMenu();
pMenu->EnableMenuItem(nCommand, bEnable ? 0 : MF_DISABLED | MF_GRAYED);
DrawMenuBar();
}
I think you should add an ON_UPDATE handler for your menu ID. This would ensure that the menu is enabled/disabled when you want to.