Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / MFC

MZCrumbBar - A Generic Breadcrumb Controller

4.95/5 (50 votes)
15 Nov 2010CPOL3 min read 1   1.8K  
A generic MFC breadcrumb controller that shows a clickable breadcrumb list.

MZCrumbBarDemo

Introduction

I needed a breadcrumb bar like the one in Windows Vista so I could show a path and have the path to be clickable. But I also needed a crumb-bar in another project, and it had nothing to do with file paths. So I built this CrumbBar controller that is generic. It can show any string with delimiters as a crumb-bar.

Features

  • Any string with a delimiter can be shown as a crumbbar:
  • CrumbBar showing a none file path

  • Can go into Edit mode if clicked on (configurable on what clicks will turn it to editable).
  • Go into edit mode if clicked on

  • Send notification on what item was clicked. Notifications can be sent for both single and double clicks on all three mouse buttons.
  • Support 'go back' item if not all crumb items fit in the controller.
  • Go into edit mode if clicked on

  • Support left margin and item spacing.
  • Support gradient background.
  • Can easily be custom drawn to implement your own drawing of the crumb items.
  • Custom draw of crumbbar items

Create the Controller

Adding MZCrumbBar to a dialog:

Custom Control Properties

  1. Added a custom controller to the layout where you want to have it.
  2. Set the ID of the properties to something like IDC_CRUMBBAR.
  3. Class name in properties must be "MZCrumbBarCtrl".
  4. Then set the style flags you want, like 0x50810001. If you do not want any border (WS_BORDER), remove 0x00800000 from the value.
  5. Then add a MZCrumbBar variable to your dialog class.
  6. To connect the custom controller in the dialog layout with the m_CrumbBar variable, you need to add some code into DoDataExchange:
  7. C++
    void CCrumbBarDemoDlg::DoDataExchange(CDataExchange* pDX)
    {
        CDialog::DoDataExchange(pDX);
        DDX_Control(pDX, IDC_CRUMBBAR, m_CrumbBar);
    }
  8. Then configure the controller how you want it in OnInitDialog().

Configuring

Here are the options on when the controller should turn into Edit mode. Set them as StyleEx flags in Create, or with MZCrumbBar::Style(...).

C++
#define CRU_EDITOUTSIDE   0x00000010 // Click must be outside of crumb items. 
#define CRU_EDITONCLK_L   0x00000100 // Enter Edit mode on Left Click
#define CRU_EDITONDBL_L   0x00000200 // Enter edit mode on Left DblClick 
#define CRU_EDITONCLK_R   0x00000400 // Enter Edit mode on Right Click 
#define CRU_EDITONDBL_R   0x00000800 // Enter edit mode on Right DblClick 
#define CRU_EDITONCLK_M   0x00001000 // Enter Edit mode on Middle Click 
#define CRU_EDITONDBL_M   0x00002000 // Enter edit mode on Middle DblClick 
#define CRU_LASTITEMCOLD  0x00010000 // Show no hover action for the last item 
#define CRU_LASTITEMNOCLK 0x00020000 // Do not generate click action for the last item 
#define CRU_LASTITEMNODELIMITER 0x00040000  // Do not draw a delimiter for the last item
#define CRU_DONOTSTRIPDELIMITER    0x00080000  // Do not strip double delimiter

Flags for configuring how the delimiter should be shown (set the option via the DelimiterMode(...) function):

C++
#define DM_STRIP 0 // Strip the delimiter char 
#define DM_LEFT  1 // Show Delimiter in the Left part 
#define DM_RIGHT 2 // Show Delimiter in the right part 

Set Colors and Margins

C++
m_CrumbBar.ColorDefault( RGB(255, 0, 0));
m_CrumbBar.ColorHot( RGB(255, 0, 0));
m_CrumbBar.BackgroundColor( RGB(255, 0, 0), RGB(0,0,0), true);
m_CrumbBar.Margin(10);
m_CrumbBar.ItemSpacing(6);

Using the Crumbbar

C++
// Initializing the CrumbBar.
m_CrumbBar.Path(_T("C:\\MyFolder\\SubFiles1\\SubFolder2\\")); 
m_CrumbBar.Delimiter(_T("\\"));
m_CrumbBar.DelimiterMode(DM_RIGHT);

// Create a PreItem and set the preitem to "..\\"
MZCrumbBar::CrumbBarItem PreItem(_T(""), _T("..\\")); 
m_CrumbBar.PreItem(PreItem); 

// Rebuild/Update the CrumbBar.
m_CrumbBar.BuildCrumbbar();

// Get The Complete path.
CString path = m_crumbBar.Path();

// Get the path up to and including a specific CrumbBar item.
CString path = m_crumbBar.GetPath( pCrumbBarItem );

Notifications

There are a few notification messages that are used to notify the owner window when things have happened:

C++
#define NMCB_LBCLICK    1000 // User clicked with Left Mouse Button 
#define NMCB_RBCLICK    1001 // User clicked with Right Mouse Button 
#define NMCB_MBCLICK    1002 // User clicked with Middle Mouse Button 
#define NMCB_LBDBLCLICK 1003 // User double clicked with Left Mouse Button 
#define NMCB_RBDBLCLICK 1004 // User double clicked with Right Mouse Button 
#define NMCB_MBDBLCLICK 1005 // User double clicked with Middle Mouse Button 
#define NMCB_EDITCHANGE 1010 // User changed path by editing it

To catch the notification message, you can do this in your dialog:

C++
// in .h file
afx_msg void OnCrumbBarItemClicked(NMHDR *pNotifyStruct, LRESULT* pResult) ;

// in .cpp file
BEGIN_MESSAGE_MAP(CCrumbBarDemoDlg, CDialog)
    ON_NOTIFY( NMCB_LBCLICK, IDC_CRUMBBAR , OnCrumbBarItemClicked) 
END_MESSAGE_MAP()

void CCrumbBarDemoDlg::OnCrumbBarItemClicked(NMHDR* pNotifyStruct, LRESULT* pResult) 
{
    NM_CRUMBBARITEM* pnmCrumbBarItem = (NM_CRUMBBARITEM*)pNotifyStruct;

    // CrumbBar Item that was clicked
    pnmCrumbBarItem->pCrumbBarItem;

    // CrumbBar Path for clicked item
    pnmCrumbBarItem->strCrumbPath;

    // Mouse position when click happen.
    // used for example to show a context menu with sub folder, 
         // like Explorer in Windows Vista
    pnmCrumbBarItem->pt;

    ...
}

Custom Draw the CrumbBar Items

Custom draw of crumbbar items

Custom draw of crumbbar items

To change the CrumbBar to a custom look, you need to override a couple of functions.

C++
// Return the width of the crumbbar item.
virtual int OnMeasureItem(CDC* pDC, CrumbBarItem* pItem);

// Return width if the PreItem (item that is shown at the beginning, 
// if not all crumbbar items can be drawn)
virtual int OnMeasurePreItem(CDC* pDC);

// Draw CrumbBar Item
virtual void DrawCrumbItem(CrumbBarItem* pItem, CDC* pDC, CRect rc);

// Draw PreItem
virtual void DrawPreItem(CrumbBarItem* pItem, CDC* pDC, CRect rc);

Take a look at CBlockCrumbBar.h/.cpp in the source for the demo app to see how it can be done.

Credits

  • Borrowed Gradient code from CLabel by Norm.net

History

For full history, check the header in MZCrumbBar.cpp.

  • v1.3: 2010-11-13
    • Added new flag CRU_DONOTSTRIPDELIMITER that will keep the double delimiter.
    • Double delimiter is used to tell MZCrumbarCtrl that it should not break a path when it sees a delimiter.
    • E.g.: "Main-Sub-Sub--Menu" -> last item is normally shown as "Sub-Menu", but with this flag, it is shown as "Sub--Menu". Since the double delimiter is not stripped, for example "\\Server\Share\Folder" -> the first item will now be shown as "\\Server" and not as "\Server".

  • v1.2: 2010-04-15
    • Added improvements/fixes provided by Iain Clarke
      • Three more BuildCrumbbar(...) functions for special situations.
      • Refactored how a path is parsed.
      • Added CRU_LASTITEMNODELIMITER. If style is set, the delimiter will not be shown for the last crumb-bar item.
      • Style can now be set using styleEx.
      • Changed default hot color to COLOR_HOTLIGHT.
      • Added possibility to store custom data in a crumb-bar item.
      • Added SetItemData/GetItemData of custom data to crumb-bar items.
    • Fixed so that double delimiter now works again. Double delimiter should be part of the crumb-path name and not split the path.
    • Changed so that items are added to m_vCrumbItems via the virtual function AddCrumbItem(...).
    • Fixed so that empty path parts are not added to the path.
  • v1.1 - 2010-03-17 - First public version. Fixed minor draw issue.
  • v1.0 - 2009-10-10 - First version.

License

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