Click here to Skip to main content
Click here to Skip to main content
Go to top

Switchboard User Interface

, 6 Jan 2004
Rate this:
Please Sign up or sign in to vote.
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 –
// PageNo ItemIndex ItemCaption GoToPageNo CmdToInvoke IconID
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

Share

About the Author

amkarkha

United States United States
No Biography provided

Comments and Discussions

 
GeneralIt is not clear how to hide the panel... Pinmemberandrewtruckle12-Apr-06 1:02 
GeneralCool Control...Thanks! But I need reduce height Pinmemberalwayzgreat13-Jan-05 4:05 
GeneralRe: Cool Control...Thanks! But I need reduce height Pinmemberamkarkha21-Jan-05 15:03 
GeneralA design note Pinmemberpeterchen3-Jan-04 1:04 
GeneralRe: A design note Pinmemberamkarkha5-Jan-04 15:07 

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

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

| Advertise | Privacy | Mobile
Web02 | 2.8.140916.1 | Last Updated 7 Jan 2004
Article Copyright 2004 by amkarkha
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid