Click here to Skip to main content
15,881,687 members
Articles / Desktop Programming / MFC
Article

Switchboard User Interface

Rate me:
Please Sign up or sign in to vote.
4.36/5 (22 votes)
6 Jan 20047 min read 93.3K   4.8K   51   5
Switchboard User Interface for hierarchical data.

Sample image

Introduction

The class CSwCtl (derived from CControlBar) fixes itself on the left hand edge of the main frame and can be used to provide a user interface for any tree like hierarchy of data, typically as a starting point user interface for your app.

An example for a real world application could be a financial software’s reporting module node that fans out into sub levels. E.g., Dealer reports, Accounting reports, Management Reports, each having its own special reports.

Somewhat similar controls that I came across while browsing the web, were not meant to support more than two levels. That’s where I felt that CSwCtl could be useful for cases that need to show any number of levels of the tree like data. Nevertheless, I must mention that CSwCtl is greatly, rather solely, inspired from an earlier contribution made by Dheth at Code Project as 'Outlookbar' based on CControlBar, titled 'Outlookbar-style menu interface'. He has provided a very elegant solution that serves for a generic purpose. CSwCtl rather focuses on a specific requirement. I have to mention further that the idea of CSwCtl is not new. Those of you who have had a chance to look at MS Access development env, would quickly relate the identity of CSwCtl with Switchboard. CSwCtl enhances, in a bit, this concept by providing a default mechanism to handle history of upto 10 item clicks and albeit offers a better look-n-feel. You will also realize that the strength of CSwCtl lies in the fact that you can programmatically manage this starting point UI of your app. E.g., depending on the user levels (admin user, power user, ordinary user) you can control which modules are available to the current user.

I have been able to use it for my own work on Win XP and found that it's meeting what I was wanting. I hope it helps you too.

Background

To understand the concept, imagine each level of your module hierarchy as a page. Each page has items on it.

Thus in the above tree, first page will contain –

  • Finance
  • Production
  • Reports
  • Tools

Another page (say page number ‘n’) will have –

  • Loans
  • Collections
  • Accounting ….

Another page (say page number ‘m’) will have -

  • Enterprise Tools
  • Standard Tools

And you will use CSwCtl::AddItem() to link these pages and arrange them in a logical sequence, e.g. Finance will point to page n, Tools will point to page m.

Using the code

In short,

You need to call 3 functions of CSwCtl in your main frame’s OnCreate().

  • Create() to create.
  • AddItem() to Configure the control bar to suit your needs.
  • AddItem()

:

Init() to initialize and err check.

Details

  1. Add the two files (SwCtl.h and SwCtl.cpp) to your project.
  2. Add the following line to your application’s Main frame (CFrameWnd derived class) header file.
    #include "SwCtl.h"
  3. Add a member variable (say m_wndSwCtl) along with the statusbar and toolbar as follows:
    CSwCtl m_wndSwCtl;
  4. In the OnCreate() function of your main frame class, add the following line BEFORE creating the toolbar or statusbar.
    if (!m_wndSwCtl.Create(1,this)) return -1;
  5. Customize the CSwCtl using the AddItem() member function as –
//PageNoItemIndexItemCaptionGoToPageNoCmdToInvokeIconID
m_wndSwCtl.AddItem(0,0,"AllModules",0,0,IDI_1)
m_wndSwCtl.AddItem(0,1,"Finance",1,CMD_FIN,IDI_2)
m_wndSwCtl.AddItem(0,2,"Production",2,CMD_PROD,IDI_3)
m_wndSwCtl.AddItem(0,4,"Reports",3,CMD_REPT,NULL)
m_wndSwCtl.AddItem(0,5,"Tools",7,CMD_TOOL,IDI_4
and so forth ...
  • PageNo – decides the page on which this item will be placed. Page numbers must be 0 or more. First page must be numbered 0. While using AddItem(), remaining pages need not fall in sequence. Init() will assert if PageNo is less than 0.
  • ItemIndex – decides the position where the item/button will appear when the page is displayed. Thus PageNo and ItemIndex decide the place of an item on the UI. You may skip some numbers in order to space out some items from other. (For example, on the first page, Reports and Tools menu are separated from Finance and Production menus by skipping ItemIndex 3). Index=0 is reserved from the item that appears on the header section of the page and Index for menu buttons should start from 1. Thus whatever you mention for 0th item will appear on the header button. This header button will be non-clickable, and will only serve as a title for that page.

    Init() will assert if Index is less than 0.

  • CmdToInvoke - You will want to call a certain functionality (e.g. launch a form, run an app) when user clicks on a menu button. At step 7, you define the eCommandID enum in Main frame where you assign a distinct number for each module/functionality and pass it to AddItem() as that item’s CommanID. Thus in above example, CommandIDs are CMD_FINANCE , CMD_PRODUCTION , CMD_TOOLS etc. Some items may not require any command to be invoked such as items that serve as a root node for its children nodes. For example, Tools menu has two sub nodes viz. Enterprise Tools and Standard Tools. Thus the Tools node itself does not invoke any command. It rather serves as a fork leading to its children. For such an item where you do not have a command handler, you pass CmdID as -1.
  • GoToPageNo – when a user clicks on an item/button, you might want to show the next level of hierarchy. This is the page number of that next level. In the above example, the Finance menu should lead to a page that contains its sub menus (Loans, Mortgages etc). Thus Finance Menu’s GoToPageNo will be a page that contains these sub menus. Items on the last level will have GoToPageNo = current page number, since there is no need to display a different page on the last level. GoToPageNo number must be greater than 0. Init() will assert if you assign a page number that does not exist.
  • IconID and ItemCaption represent the res ID of the icon and string that appears on the item.
  1. After adding all the items, call the Init() method of CSwCtl. This is VERY IMPORTANT. Init() will do a consistency check on the customization you did using AddItem() and it also does the ground work for display mechanism.
    if(!m_wndSwCtl.Init()) return -1;
  2. Define an enumeration (in your main frame’s header file) that best describes your modules.
     enum 
    eCommandID
     {
      CMD_FINANCE,
      CMD_PRODUCTION,
      CMD_TOOLS,
      :
      :
    };
  3. In the InvokeCommand() function of CSwCtl, add the dispatching code as follows:
    switch(nCmdID){
    case CMD_FINANCE:
       MessageBox("Your code to handle the Finance Module goes here.");
       break;
    case CMD_PRODUCTION:
       MessageBox("Your code to handle the Production Module goes here.");
    :
    :
  4. The source files (SwCtl.h and .cpp) alone can not provide you with the icons for Previous, Main Menu and Next button. You will be required to create/import these three icons and assign their IDs to these lines in SwCtl.h
    //Assign IDs corresponding to the icons you created 
    // for Main, Prev and Next buttons for following 3 items.
    #define ICONID_MAIN IDI_MAIN   //<- Change to your 
                                   // Main Menu button Icon ID 
    #define ICONID_PREV IDI_PREV   //<- Prev 
    #define ICONID_NEXT IDI_NEXT   //<- Next

    Lastly, you will have to create the menu IDR_STYLE as done in the demo project.

Take a note of #define WINVER 0x0400 in SwCtl.h. This should allow you to avoid using the GradiantFill() that might hurt VC6 users.

Following these steps, I was able to build and use CSwCtl with VC6 and VC7 on Win2k and XP. Hope things work out smooth for you too.

Points of interest

  • Array of items, that forms quite a normalized data structure. It's extensible and yet intuitive. You will be able to add your own extensions to the existing data of an item (e.g. Tooltips, changing background color for each page ...). Thanks to the original idea from Access.
  • Fact that the UI can be programmatically configured to show/hide modules selectively depending on some criteria (say user levels).
  • Double click of right mouse switches between small icon look to large icon look. This too can be programmatically controlled by setting m_bBigIcons member variable to true.
  • As you will notice, CSwCtl is more a CWnd class than a CControlbar class. This makes it quite an easy tweak to use in a Dialog based applications as well.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralIt is not clear how to hide the panel... Pin
andrewtruckle12-Apr-06 1:02
andrewtruckle12-Apr-06 1:02 
GeneralCool Control...Thanks! But I need reduce height Pin
alwayzgreat13-Jan-05 4:05
alwayzgreat13-Jan-05 4:05 
GeneralRe: Cool Control...Thanks! But I need reduce height Pin
amkarkha21-Jan-05 15:03
amkarkha21-Jan-05 15:03 
GeneralA design note Pin
peterchen3-Jan-04 1:04
peterchen3-Jan-04 1:04 
GeneralRe: A design note Pin
amkarkha5-Jan-04 15:07
amkarkha5-Jan-04 15:07 

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.