XBreadCrumbBar - Draw breadcrumb trail with hyperlinks and HTML





5.00/5 (21 votes)
XBreadCrumbBar is a windowless non-MFC class that allows you to display a breadcrumb trail as HTML text, with support for web links and APP: links.
Introduction
According to Wikipedia,
Here is typical way breadcrumbs are used on web:
And of course Google also uses breadcrumbs:
Use of breadcrumbs is becoming widespread on the web, and has started to show up in PC apps as well. Vista Windows Explorer uses breadcrumbs to show where you are in file system:
Breadcrumb navigation seems particularly well-suited to any kind of hierarchical system, and serves two purposes: first, to show you where you are in hierarchy; and second, to allow you to navigate to a previous point in hierarchy in a random-access fashion - in other words, you do not have to keep hitting back button, you can just click on second link and immediately go to second location in breadcrumb trail.
While most studies of breadcrumb navigation have been focused entirely on web sites (see references), there are many similarities between navigating a web site and navigating a non-trivial PC app, especially one that deals with hierarchical data - for example, HR systems, auto parts ordering systems, and software for presenting and selecting class schedules. Jakob Nielsen, a user interface expert, has an interesting blog about breadcrumbs. If you replaced the words "web site" with "PC app" in his blog, it would still make perfect sense.
Breadcrumb navigation seemed appropriate for a large inventory system I was recently involved with, and the client liked the idea when I presented it to him. This led to the creation of XBreadCrumbBar, which is based on XHtmlDraw. This gives additional flexibility in the visual display of the breadcrumb trail, and also offers built-in support for both web links and APP: links (see my XHtmlDraw article for more details).
XBreadCrumbBar Features
Let me start by showing you the demo app:
Here are main features:
- The No Links breadcrumb shows a static breadcrumb trail with no links. The text is displayed using bold font, as is the separator.
- The Web Links breadcrumb shows use of colors for links, copied from my favorite book site. The last crumb is different color and is not a link. Note that crumbs are bold, while separator is not.
-
The APP: Links breadcrumb shows different colors for each link,
with cursor on first link. When link is clicked,
this is what you will see:
XBreadCrumbBar Implementation
The class CXBreadCrumbBar
is derived from CXHtmlDraw
,
which you can find described in
this article,
and embeds the link-handling class CXHtmlDrawLink
,
also described in
CXHtmlDraw
article.
Here are functions of CXBreadCrumbBar
class:
Function | Description |
---|---|
int Draw(HWND hWnd, BOOL bUnderlineUrl, int index = -1) | Draw the XBreadCrumbBar to hWnd. If index = -1, draw all crumbs, otherwise only draw specified crumb. |
int Draw(HDC hdc, BOOL bUnderlineUrl, int index = -1) | Draw the XBreadCrumbBar to hdc. If index = -1, draw all crumbs, otherwise only draw specified crumb. |
BOOL GetBoldSeparator() | Get state of bold flag for separator |
int GetCount() | Retrieve number of crumbs |
XHTMLDRAWSTRUCT * GetDrawStruct(int index) | Retrieve draw struct for crumb specified by index |
size_t GetCrumb(int index, BOOL bStripHtml, LPTSTR pszCrumb, size_t size) | Retrieve crumb string for crumb specified by index. If pszCrumb is NULL, only the crumb length (in TCHARs) is returned. |
int GetCrumb(LPCTSTR lpszCrumb, BOOL bStripHtml) | Retrieve crumb index for crumb whose string matches lpszCrumb |
CXHtmlDrawLink * GetLinks() | Retrieve pointer to CXHtmlDrawLink object, used for web and APP: links |
int GetCrumbs(TCHAR *** crumbs) | Retrieve pointer to array of pointers to crumb strings |
TCHAR * GetSeparator() | Retrieves pointer to separator string |
CXBreadCrumbBar& InitDrawStruct(XHTMLDRAWSTRUCT * pXHDS, BOOL bBoldSeparator = TRUE) | Initialize draw struct |
int IsAnchorUnderlined() | Returns index number of crumb that is underlined, otherwise returns -1 |
int IsOverAnchor(HWND hWnd) | Returns index number of crumb that mouse is over, otherwise returns -1 |
BOOL RelayClick(HWND hWnd) | Relays click event to CXBreadCrumbBar |
void RelayMouseMove(HWND hWnd) | Relays mouse move to CXBreadCrumbBar |
CXBreadCrumbBar& SetAppCommands(XHTMLDRAW_APP_COMMAND * paAppCommands, int nAppCommands) | Sets up table for APP: commands |
CXBreadCrumbBar& SetBoldSeparator(BOOL bBold) | Sets separator bold flag: if TRUE, separator will be bold when crumb is bold; if FALSE, separator will not be bold, even when crumb is bold |
CXBreadCrumbBar& SetCrumbs(const TCHAR * crumbs[], int count) | Set crumb strings from array of strings |
CXBreadCrumbBar& SetCrumbs(LPCTSTR crumbs, TCHAR sepchar) | Set crumb strings from character-separated string, where character is specified by sepchar |
CXBreadCrumbBar& SetSeparator(LPCTSTR lpszSep) | Sets separator string |
How To Use
Follow these steps to integrate XBreadCrumbBar into your app:
Step 1: Add XBreadCrumbBar Files
Add following files to your project:
- XBreadCrumbBar.cpp
- XBreadCrumbBar.h
- XHtmlDraw.cpp
- XHtmlDraw.h
- XHtmlDrawLink.cpp
- XHtmlDrawLink.h
- XNamedColors.cpp
- XNamedColors.h
- XString.cpp
- XString.h
Step 2: Define Persistent CXBreadCrumbBar Object
In the demo app, there are three CXBreadCrumbBarM
objects
defined in XBreadCrumbBarTestDlg.h:
CXBreadCrumbBar m_ccb[3];
Step 3: Initialize XHTMLDRAWSTRUCT Struct
The XHTMLDRAWSTRUCT struct
contains formatting information
and screen position for XBreadCrumbBar. Here is the
initialization function from demo app:
//================================================================= void CXBreadCrumbBarTestDlg::InitDrawStruct(int index) //================================================================= { ASSERT((index >=0) && (index < 3)); LOGFONT lf; memset(&lf, 0, sizeof(LOGFONT)); CFont *pFont = GetFont(); // get font for the dialog if (pFont) pFont->GetLogFont(&lf); CWnd *pWnd = GetDlgItem(g_uStatic[index]); ASSERT(pWnd); CRect rect; pWnd->GetWindowRect(&rect); ScreenToClient(&rect); rect.DeflateRect(5, 5); rect.top += 10; CXBreadCrumbBar::XHTMLDRAWSTRUCT ds; ds.crText = m_rgbText; ds.nID = index; if (index == 0) ds.crText = RGB(119,121,118); if (index == 1) ds.crBackground = GetSysColor(COLOR_BTNFACE); else ds.crBackground = m_rgbBackground; ds.rect = rect; if (index != 2) ds.bBold = TRUE; else ds.bBold = FALSE; ds.bLogFont = TRUE; if (index == 0) _tcscpy(lf.lfFaceName, _T("Arial")); memcpy(&ds.lf, &lf, sizeof(LOGFONT)); if (index == 0) m_ccb[index].SetSeparator(_T(" > ")); // must set crumbs before calling CXBreadCrumbBar::InitDrawStruct switch (index) { default: case 0: // all crumbs in one string, separated by '~' m_ccb[index].SetCrumbs(SAMPLE_1, _T('~')); break; case 1: // array of 4 strings m_ccb[index].SetCrumbs(SAMPLE_2, 4); break; case 2: // array of 5 strings m_ccb[index].SetCrumbs(SAMPLE_3, 5); break; } // don't use bold separators in second bread crumb bar m_ccb[index].InitDrawStruct(&ds, (index == 1) ? FALSE : TRUE); }
Step 4: Initialize APP: Commands
APP:
hyperlinks allow you to display hyperlinked text that sends a
Windows message to a specified window when user clicks on it.
To use APP:
hyperlinks, you must set up
APP: command table - here is table used
in the demo app:
CXHtmlDraw::XHTMLDRAW_APP_COMMAND AppCommands[] = { { m_hWnd, WM_APP_COMMAND_1, 1, _T("WM_APP_COMMAND1") }, { m_hWnd, WM_APP_COMMAND_2, 2, _T("WM_APP_COMMAND2") }, { m_hWnd, WM_APP_COMMAND_3, 3, _T("WM_APP_COMMAND3") }, { m_hWnd, WM_APP_COMMAND_4, 4, _T("WM_APP_COMMAND4") }, { m_hWnd, WM_APP_COMMAND_5, 5, _T("WM_APP_COMMAND5") }, };This table has five entries, but you can add as many entries as you need. Each entry has four elements: the first is the
HWND
of the
window that is to receive the message; the second is the numeric message
number that will be sent to the window via SendMessage()
; the
third is user-defined data that is returned in the wParam member; and the
fourth is a string that ties the table entry to the HTML code.
After setting up this table, pass it to the CXBreadCrumbBarM
object by calling SetAppCommands()
:
m_ccb[2].SetAppCommands(AppCommands, sizeof(AppCommands)/sizeof(AppCommands[0]));
You can call SetAppCommands()
as often as you need to,
if crumbs are changing dynamically.
Step 5: Track Mouse Movement
Since CXBreadCrumbBar
is windowless, you must
add code to relay mouse moves to CXBreadCrumbBar
.
Here is OnMouseMove()
function
from demo app:
//============================================================================= void CXBreadCrumbBarTestDlg::OnMouseMove(UINT nFlags, CPoint point) //============================================================================= { for (int i = 0; i < 3; i++) m_ccb[i].RelayMouseMove(m_hWnd); CDialog::OnMouseMove(nFlags, point); }
Step 6: Handle Mouse Clicks
Again, since CXBreadCrumbBar
is windowless, you must
add code to relay clicks to CXBreadCrumbBar
. Here is
OnLButtonUp()
function from demo app:
//============================================================================= void CXBreadCrumbBarTestDlg::OnLButtonUp(UINT nFlags, CPoint point) //============================================================================= { for (int i = 0; i < 3; i++) { if (m_ccb[i].RelayClick(m_hWnd)) break; } CDialog::OnLButtonUp(nFlags, point); }
References
Links to information on breadcrumb navigation:
- Wikipedia: Breadcrumb navigation
- Breadcrumb Navigation: Further Investigation of Usage
- Influence of Training and Exposure on the Usage of Breadcrumb Navigation
- Jakob Nielsen: Breadcrumb Navigation Increasingly Useful
- Keith Instone: Location, Path & Attribute Breadcrumbs
- Breadcrumb Navigation
- Hansel and Gretel
Links to articles I have used in demo app:
- XHtmlDraw - Draw text with HTML tags and anchor links
- XHyperLink - yet another hyperlink control
- XMessageBox - A reverse-engineered MessageBox()
- XString - non-MFC non-STL string functions
Revision History
Version 1.0 - 2007 August 7
- Initial public release
Usage
This software is released into the public domain. You are free to use it in
any way you like, except that you may not sell this source code. If you modify
it or extend it, please to consider posting new code here for everyone to share.
This software is provided "as is" with no expressed or implied warranty.
I accept no liability for any damage or loss of business that this software
may cause.