|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
IntroductionI wanted a floating toolbar in my application in addition to the standard docked toolbar. The floating toolbar isn't dockable. Thus it always looks like this:
See that little 'x' in the top right corner? All I wanted was to disable it so that the user couldn't dismiss the toolbar. As you'd guess, it turned out to not be terribly obvious how to disable it. BackgroundThere are a number of variations on the Toolbar in MFC. We haveCToolBar, CDialogBar and so on. I chose
CToolBar as my base class. In MFC SDI applications you create your toolbars in the MainFrame's OnCreate()
member function and do the appropriate voodoo to dock or float them. In my application it looks like this.
if (!m_wndToolBar.CreateEx(this) || !m_wndToolBar.LoadToolBar(IDR_TOOLBAR))
{
TRACE0("Failed to create toolbar\n");
return -1; // fail to create
}
CPoint pt(0, 25);
ClientToScreen(&pt);
m_wndToolBar.EnableDocking(0);
FloatControlBar(&m_wndToolBar, pt);
which creates the toolbar, disables docking for that particular toolbar and calls FloatControlBar() specifying the
initial screen coordinates for the toolbar.
We know that the window handle exposed in our Digging around in the window heirarchy using Spy++ reveals that the window handle contained in the Time to turn to the MFC source code. Cutting a long story short, after creating the Toolbar Control Window you choose either to dock it or float it. In either
case an CMiniDockFrameWndThis is an undocumented helper class in MFC derived fromCMiniFrameWnd. The framework creates a
CMiniDockFrameWnd whenever it needs one and does the appropriate magic to wire our Toolbar Control to it, and to
wire it to our MainFrame window.
The standard approach to this problem might be to derive our own class from Unfortunately this approach won't work. The problem is there's no way to derive a new class from So we have to find another way. How about subclassing the My final solutionis maybe somewhat 'quick-and-dirty' but it works quite well. The solution is to navigate up the window heirarchy from the ToolBar Control Window to theCMiniDockFrameWnd, get the system menu and disable the 'Close' item. This disables the close
button. I also remove the 'Close' item from the menu. The latter is done because you can right click on the toolbar caption and
get access to the system menu. The code looks like this.
void CMyToolBar::DisableCloseButton()
{
// Now remove the Hide menuitem so obligingly
// installed for us by the CMiniDockFrameWnd
// class. We do this by navigating 2 levels
// up from our toolbar to the enclosing
// frame window and modifying its system menu.
CWnd *pWnd = GetParent();
if (pWnd != (CWnd *) NULL)
{
ASSERT_KINDOF(CWnd, pWnd);
pWnd = pWnd->GetParent();
}
if (pWnd != (CWnd *) NULL)
{
ASSERT_KINDOF(CWnd, pWnd);
// Make sure the window we found isn't our MainFrame
// window.
if (pWnd->GetSafeHwnd() != AfxGetMainWnd()->GetSafeHwnd())
{
CMenu *pSysMenu = pWnd->GetSystemMenu(FALSE);
if (pSysMenu != (CMenu *) NULL)
{
ASSERT_KINDOF(CMenu, pSysMenu);
pSysMenu->DeleteMenu(1, MF_BYPOSITION);
pSysMenu->EnableMenuItem(SC_CLOSE, MF_BYCOMMAND | MF_DISABLED);
pSysMenu->DeleteMenu(SC_CLOSE, MF_BYCOMMAND);
}
}
}
}
The code is based on the assumption that there's a menu attached to the grandparent of our ToolBar window. That'll be true both
for docked and floating windows in the current incarnation of MFC7. As a safety check we ensure that we're not modifying
the system menu for our MainFrame. We also check the validity of our assumptions at each step by verifying that the pointers
we get back are valid.
Using the codeAdd the two files in the source download to your project. You probably want to give the class a better name thanCMyToolBar.
In your CMainFrm class change the CToolBar to be a CMyToolBar. Then, sometime early in the
life of the Toolbar but after the MainFrame window has been created and after you've called the FloatControlBar()
function you call the DisableCloseButton() function. The demo project shows how this is done. Voila!
Other notesInterestingly enough, deep within the bowels ofCMiniDockFrameWnd is some code to modify the system menu. The 'Close'
menuitem is removed and added back in with 'Hide' as the text. The WM_CLOSE handler doesn't actually close a
CMiniDockFrameWnd, it merely hides it. The Toolbar can be made visible again by calling
CFrameWnd::ShowControlBar().
History11 April 2004 - Initial version
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||