Click here to Skip to main content
15,886,519 members
Articles / Desktop Programming / MFC

Tool Group Manager

Rate me:
Please Sign up or sign in to vote.
3.50/5 (3 votes)
23 Aug 2000CPOL 75.2K   1.7K   27   2
A reusable template class for managing multiple toolbars, only one of which is displayed at a time.

Sample Image - ToolGroupManager.gif

Introduction

Toolbars are a great user interface widget, but when an application has a large number of toolbars they can quickly become unmanageable. Providing facilities for the user to toggle toolbars on and off is all very well. The downside is that the use of the facility distracts the user from their task. I ran into exactly this problem in a recent application, and attempted to find a solution. Ultimately I came up with the Tool Group Manager that I present here.

The idea is to have a high level toolbar that present the user with overall options, rather than specific options. On selecting an overall option, another toolbar is displayed subdividing the group into specifics. The last specific option is maintained automatically to minimize user effort.

In the article Changing toolbars dynamically at runtime by Masoud Samimi, it shows how to dynamically replace toolbars at runtime. As it turns out, these two articles are very similar, but it is still appropriate to present my alternative. I do not profess this method to be in any way better than Masoud's, simply an alternative that I developed for my own needs.

How to use the class

As much of the functionality as possible is wrapped into a single template class called TToolGroupManager. A few changes are must be made to the main window. The class has a very small public interface, consisting of a constructor, destructor and two alternative methods of adding toolbars.

C++
template<class FRAMEWND>
class TToolGroupManager : public CCmdTarget
{
    ...

  public:
    TToolGroupManager(FRAMEWND *pFrameWnd);
    virtual ~TToolGroupManager();
    void AddToolGroup(WORD wID, CToolBar *pToolBar);
    void AddToolGroups(const WORD wIDs[], CToolBar *pToolBar, int nCount);

    ...
};

In the true tradition of MFC, I have declared a macro to make implementation easier. In the frame window of your application, instantiate the template class and add the IMPLEMENT_TOOLGROUPMANAGER macro. You will also need to create an array of CToolBar objects for the dynamic toolbar controls.

C++
class CMainFrame : public CFrameWnd
{
  private:
    CToolBar m_tbTool[3];
    TToolGroupManager<CMainFrame> m_ToolGroupManager;

    ...

    IMPLEMENT_TOOLGROUPMANAGER
    DECLARE_DYNCREATE(CMainFrame)
    DECLARE_MESSAGE_MAP()
};

Now, in you main frame's implementation (.cpp) file, declare an array of WORDs containing the resource IDs of the main tool groups (the resource IDs do not have to be contiguous). Next, create a MFC message map for the template containing an ON_COMMAND and ON_UPDATE_COMMAND_UI entry for each of the array entries. Currently this is the easiest way to automate this process, as the information is required at compile time to build MFC's message map array.

C++
const WORD nToolGroup[] = { ID_TOOL1, ID_TOOL2, ID_TOOL3 };
BEGIN_MESSAGE_MAP(TToolGroupManager<CMainFrame>, CCmdTarget)
    //{{AFX_MSG_MAP(TToolGroupManager)
    //}}AFX_MSG_MAP
    ON_COMMAND(nToolGroup[0], OnToolGroup)
    ON_COMMAND(nToolGroup[1], OnToolGroup)
    ON_COMMAND(nToolGroup[2], OnToolGroup)
    ON_UPDATE_COMMAND_UI(nToolGroup[0], OnUpdateToolGroup)
    ON_UPDATE_COMMAND_UI(nToolGroup[1], OnUpdateToolGroup)
    ON_UPDATE_COMMAND_UI(nToolGroup[2], OnUpdateToolGroup)
END_MESSAGE_MAP()

The TToolGroupManager constructor requires a pointer to the main window, modify your CMainFrame's constructor as shown below

C++
#pragma warning(disable : 4355)
CMainFrame::CMainFrame() : m_ToolGroupManager(this)
{
}
#pragma warning(default : 4355)

The #pragma prevents a compiler warning about using the this pointer in a constructor list

The main frame implementation needs to pass command messages to our tool group manager. Use ClassWizard to add an override for the OnCmdMsg member function and call the tool group manager class as follows:

C++
BOOL CMainFrame::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) 
{
    return m_ToolGroupManager.OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)  ||
           CFrameWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}

Finally, in the OnCreate member function of the main frame, create the toolbars as you would normally. Then add them to the tool group manager. This can be done in one of two ways.

First you can add each toolbar individually, like the following example shows:

C++
int nIndex;

for (nIndex=0; nIndex < sizeof(nToolGroup)/sizeof(nToolGroup[0]); nIndex++)
    m_ToolGroupManager.AddToolGroup(nToolGroup[nIndex], &m_tbTool[nIndex]);

Or you can let the tool group manager do the work for you, like the following example shows:

C++
m_ToolGroupManager.AddToolGroups(nToolGroup, m_tbTool, sizeof(nToolGroup)/sizeof(nToolGroup[0]));

The AddToolGroup method is provided for simplicity, in the case where the toolbars are not in an array. Generally I would suspect that the AddToolGroups method would be commonly used.

Summation

That sums it up. I hope that some of you find it useful, and easy to use. Please post your comments, good or bad. Preferably good ;)

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Technical Lead
United Kingdom United Kingdom
Craig graduated with a B.SC. Honours in Computing for Real Time Systems from the University of the West of England, Bristol in 1995 after completing an HND in Computing in 1993.

Comments and Discussions

 
QuestionHi Craig, Have you tested it? Pin
Masoud Samimi28-Aug-00 8:47
Masoud Samimi28-Aug-00 8:47 
AnswerRe: Hi Craig, Have you tested it? Pin
Craig Henderson11-Sep-00 3:24
Craig Henderson11-Sep-00 3:24 
Hi all,
Sorry for the delayed reply but I have just come back from my summer holiday!
I have indeed tested the class and it works successfully in my application. To respond to your points:

A) floating the toolbars work fine on my machines, what problems do you experience?

B) Docking under the status bar is a problem with the same program rather than the class in the article, for which I do apologise. I have experienced this problem many times before and there is an easy fix, but just off the top of my head I cannot remember what it is Wink | ;)

C) Granted, I haven't tried that. What happens? Where does it fail?

D) I assume you are referring to the #pragma around the CMainFrame constructor. This is because the compiler warns against passing a this pointer to a member's constructor, although it works Ok. If you know a solution to get the same effect without a compiler warning then please share it - we are all here to learn Wink | ;)

E) The MFC class implementations do not handle the "replacing" effect by reposition the newly displayed bar where the previous one last stood. This class is intended to extend the functionality of MFC to handle the housekeeping tasks of toolbar positioning and remembering the last used tool within a group, not to replace MFC. Indeed, the class CALLS MFC to do the Show/Hide.

F) In what way do you find the main frame class confusing? It is lacking in documentation? I honestly thought that the usage of the class in the main frame was very straightforward, if there is something further I can add to clarify confusion that I would welcome constructive guidance.


The issue is not wrapping your code in a reusable wrapper. As I stated in my documentation, this code was written to my own specification long before your article appeared. It was a coincidence that you published your article a couple of days before I did, but that is all it was - a coincidence.
It is simply _a_ solution to a problem. I never claimed it to be a better solution, just a different approach.

Best Regards,
Crai

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.