Creating a Tabbed Tool Bar

Environment: compiled using VC6 on WinXP

Recently, I was involved in a project to create a 3D application. At that time I noticed the tabbed toolbar of 3D Studio Max 4 (as shown below).

Because my application required the use of a lot of tools (just like 3DS Max), I decided to implement this control. Here I shall share with you the most important details of creating the tabbed toolbar.

The implementation of the control is quite simple, actually. The control is primarily a Dialog Bar that manages a tab control and a Tool Bar. Thus, the class is derived from CDialogBar and it creates the CTabCtrl and CToolBar objects. The actual creation of the Tab control and toolbar occurs in the Create function of the Dialog Bar.

BOOL CTabToolBar::Create(CWnd* pParentWnd)
{
  if(CDialogBar::Create(pParentWnd,IDD_TBTLBAR_DLG,
    CBRS_TOP|CBRS_TOOLTIPS|CBRS_FLYBY,
    AFX_IDW_TBTLBAR))
  {
  // create the tab control.
  if(m_wndTabCtrl.Create(TCS_TABS | TCS_FIXEDWIDTH |WS_CHILD |
                         WS_VISIBLE, CRect(0,0,0,0), this,
                         IDC_TBTL_TAB))
  {
    // create tool bar.
    if(!m_wndToolBar.CreateEx(&m_wndTabCtrl))
    return FALSE;
   
   ...

   return TRUE;
  }
  return FALSE;
  }
return FALSE;
}

Note that the toolbar object is a child object of the Tab control object. There are two issues that need to be noted at this point: The Tab control has to fill the entire area of the Dialog Bar and the Toolbar should be positioned comfortably within the Tab control. This is taken care of by the OnSize function of the Dialog Bar.

void CTabToolBar::OnSize(UINT nType, int cx, int cy)
{
  ...

  if((m_wndTabCtrl.GetSafeHwnd() != NULL) &&
     (m_wndToolBar.GetSafeHwnd() != NULL))
  {
    // Get dialog bar's current dimensions.
    CRect rcWnd;
    GetWindowRect(&rcWnd);

    // Redraw Tab Control
    m_wndTabCtrl.SetWindowPos(NULL, 0, 0,rcWnd.right,
                              rcWnd.bottom, SWP_NOZORDER |
                                            SWP_SHOWWINDOW);

    // get the new toolbar position.
    CRect rcClient;
    m_wndTabCtrl.RepositionBars(AFX_IDW_CONTROLBAR_FIRST,
                                AFX_IDW_CONTROLBAR_LAST,
                                0,reposQuery,rcClient);
    rcClient.OffsetRect(2,2);

    // Redraw the toolbar.
    m_wndTabCtrl.RepositionBars(AFX_IDW_CONTROLBAR_FIRST,
                                AFX_IDW_CONTROLBAR_LAST,0,
                                CWnd::reposDefault,NULL,rcClient);
  }
}

In the code above, I would like to point out the function RepositionBars. This is a function that positions the toolbar within the Tab control. It can also be used to retrieve the client space within the Tab Control as shown in the code above.

Now what we need is to add functionality at the Change Tab events. Because in MFC there isn't any such event notification (please correct me if I am wrong), we would have to create that event ourselves. To do this, I have subclassed the CTabCtrl and defined the following variable.

// in the CFlatTabCtrl
#define USR_TABCHANGED (WM_USER+10)

As you might have noticed, I have named the class CFlatTabCtrl. Well, I thought that while I am at it, I might as well throw in a few gimmicks and made a Flat Tab Control. (Please refer to other articles for the explanation. Implementing an owner drawn Tab Control is a particularly good article for this gimmick.) Anyway, back to the problem at hand. Next, I had to check for mouse clicks on the Tab control and pump the message to the parent window (the Dialog Bar). The Dialog Bar then has to change the tab event notification that is handled by the OnChangeTab function.

Now, I would to jump to another important part of the implementation first: adding the tabs and toolbars. To facilate this, I have created the function AddItem, which primarily accepts in the tab name, toolbar resource id, and the resource id for the toolbar bitmap. An example of this can be found in the virtual function OnTabToolBarCreated. (The OnTabToolBarCreated function is called in the Create function of the CFlatTabCtrl class.)

void CTabToolBar::OnTabToolBarCreated()
{
  AddItem("Tab 1", IDR_TABTOOLBAR_1, IDB_TOOLBAR_HOT_1,
                   IDB_TOOLBAR_COLD_1);
  AddItem("Tab 2", IDR_TABTOOLBAR_2, IDB_TOOLBAR_HOT_2,
                   IDB_TOOLBAR_COLD_2);
}

This would have created a list of toolbar attributes to choose from when the tabs are selected. Back in the OnChangeTab function, all we have to do is to load the appropriate toolbar attributes and we are done.

void CTabToolBar::OnChangeTab(UINT nTabIndex)
{
  if((int)nTabIndex >= m_nItems) return;

  // Load the tool bar buttons.
  TTBITEM* pTabToolBarItem = m_pTabToolBarItems[nTabIndex];
  if(!m_wndToolBar.LoadToolBar(pTabToolBarItem->uToolBarResID))
    return;

  // Set the tool bar bitmaps.
  m_wndToolBar.SendMessage(TB_SETIMAGELIST, 0,
                          (LPARAM)pTabToolBarItem->hColdBitmap);
  m_wndToolBar.SendMessage(TB_SETHOTIMAGELIST, 0,
                          (LPARAM)pTabToolBarItem->hHotBitmap);

  // Set the new button sizes.
  m_wndToolBar.SetSizes(CSize(31,30),CSize(24,24));
}

Oh, there is actually one more thing to do. Because the Toolbar is a child of the Tab control, all command messages (such as the toolbar button clicks) are pumped to this control's class only. If you want the view class of the application to handle the messages, just route them to the CMainFrame class. I have implemented this by overriding the OnCmdMsg in both the Tab control and the Dialog Bar. This way, the messages will get pumped to the CMainFrame class. After this, MFC will take care of routing the messages to the respective CView classes.

BOOL CFlatTabCtrl::OnCmdMsg(UINT nID, int nCode, void* pExtra,
                            AFX_CMDHANDLERINFO* pHandlerInfo)
{
  if(GetParent()->GetSafeHwnd())
    return GetParent()->OnCmdMsg(nID, nCode, pExtra,
                                             pHandlerInfo);

  return CTabCtrl::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}

I guess that's it for this article but please note that this control is still far from the 3D Studio Max's Tabbed Toolbar. For example, toolbar customization and dockable toolbar (tabs can be torn off the tabbed toolbar and they would be presented as dockable) are some of the features that are not implemented in this control. I hope somebody would do that and post it up in Codeguru.

Downloads

Download demo project executable - 26 Kb
Download demo project source - 87 Kb


Comments

  • Are Herbal Remedies Effective for Treating Erectile Dysfunction?

    Posted by anieffifielm on 06/21/2013 07:11pm

    What are some Erectile Dysfunction treatments? Enjoy the sexual activity, you will automatically forget about side effect [url=http://rxhealth.pw ] homemade viagra shake with no pills [/url] read additional Sexual Revolution Referred to as Viswiss to Solve Your very own Erectile Dysfunction bother

    Reply
  • No need to override OnCmdMsg...

    Posted by Legacy on 11/05/2002 12:00am

    Originally posted by: Daniel Larocque

    Instead of overriding OnCmdMsg, you could call the CWnd::SetOwner function like this:

    m_wndToolBar.SetOwner(GetParent());

    This will redirect all the command messages from the toolbar to the main window...

    Reply
  • Can this be used in a dialog ?

    Posted by Legacy on 11/04/2002 12:00am

    Originally posted by: H Raghavendra

    Hi,

    This is really good. Can I have this dialog bar in a dialog based application.

    Please let me know the way this can be done.

    thanks
    regds
    Raghavendra H

    • Thank you!!

      Posted by tubob1982 on 05/09/2005 09:49pm

      Do more for 3ds!! Could you tell how to implement 3ds with vc6.0.

      Reply
    Reply
  • Thanks

    Posted by Legacy on 11/03/2002 12:00am

    Originally posted by: Zjj

    Would you like to do upgrade it?

    Reply
  • Hide toolbar also

    Posted by Legacy on 11/01/2002 12:00am

    Originally posted by: Chandresh Patel

    Good!

    This is so good to develop a big application with so many option.....but the only thing is when you hide toolbar also it hide tabed control automatically.....

    --Chandresh

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: December 11, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT Market pressures to move more quickly and develop innovative applications are forcing organizations to rethink how they develop and release applications. The combination of public clouds and physical back-end infrastructures are a means to get applications out faster. However, these hybrid solutions complicate DevOps adoption, with application delivery pipelines that span across complex hybrid cloud and non-cloud environments. Check out this …

  • CentreCorp is a fully integrated and diversified property management and real estate service company, specializing in the "shopping center" segment, and is one of the premier retail service providers in North America. Company executives travel a great deal, carrying a number of traveling laptops with critical current business data, and no easy way to back up to the network outside the office. Read this case study to learn how CentreCorp implemented a suite of business continuity services that included …

Most Popular Programming Stories

More for Developers

RSS Feeds