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

Control Message Bar

5.00/5 (47 votes)
23 Oct 2008CPOL10 min read 1   3.4K  
Code to add a message bar to virtually any existing Windows control.

Image 1

Introduction

I recently needed to add a message to a list when some items which would normally be shown in the list were excluded due to access permissions. I wanted a message bar which I could easily add to the control, similar in appearance to the message bar seen in most web browsers when pop-ups and other content are blocked.

How I did it

I wanted to show the message at the top of a listview control, but I didn't want to have to resize the control to fit something above the control as a sibling, so I decided to add it to the non-client area above the main client area, by intercepting the WM_NCCALCSIZE message in the control and leaving enough space to draw a message. I also wanted to provide the user with a way of dismissing the message, so I needed to respond to WM_NCLBUTTONDOWN etc. messages within the message bar area.

Not wanting to restrict myself to only being able to use the message bar in a listview control, I looked at how I could make it generic enough to be easily added to any control. My first attempt was to create a class from which I would co-inherit some MFC classes, thereby adding support for a message bar to any of my control classes. The main downside of this was that I would need a class derived from the standard MFC class for every control that I wanted to give the message bar to. I, therefore, wanted a method which allowed me to simply add the functionality to any existing control.

Adding functionality to a control by sub-classing is simple, but when the control is already sub-classed, it is not possible to subclass the control a second time. Looking into this brought me to an article by Ralph Varjabedian on Double Subclassing, which allows a previously subclassed control to be subclassed again, providing me with exactly what I needed.

Once the control has been (double-)subclassed in order to provide the message bar functionality, the message bar code is then able to intercept the window's messages, which allows it to modify the control's non-client area to provide a space for the message bar. Also, the message bar can intercept mouse messages so that the program can respond to clicks on the message bar to show a menu or perform any other action.

Some controls make their own use of the non-client area, which can interfere with the message bar's calculated area. The most common example is the list-view control, which uses the non-client area to place the column header. We are fortunate though that the list control sends a message when calculating the header's size and position, and so the message bar intercepts this message to adjust the area used by the header control, thus allowing it to keep its own space.

How to use it

Using the CCtrlMessageBar class is simple. Follow the steps below to add one to an existing project:

  1. After putting the source files (CtrlMessageBar.cpp and CtrlMessageBar.h) into the directory you wish to use them from, add the files to your Visual Studio project.
  2. Make sure you have a control to which you wish to add the message bar. I'll assume this is a list control, with a variable name of m_list.
  3. Add a CCtrlMessageBar variable to your dialog class. I'll assume this is called m_barList.
  4. Add a handler for WM_INITDIALOG in your dialog class if you don't already have one, and add the following code to it to add a message bar and set its text:
  5. m_barList.Attach(m_list);
    m_barlist.SetText(_T("This is my message bar text"))
  6. You can set an image for the bar by attaching an image list and setting the image index to use:
  7. CImageList imlMessageBar;
    ...
    
    m_barList.SetImageList(imlMessageBar);
    m_barList.SetImage(3);

That's all you need to do to get started. See the features or member function documentation below, or the demo application, for more advanced options.

Features

Some of the features included in the control, which you may find useful, are as follows:

Bars may have images

As in the example above, you may optionally set an image-list for the message bar, and then specify an image in that image-list to be displayed at the top left of the bar.

Text may be set to wrap

Text that is too long to fit in the bar's rectangle may be set to wrap, by calling the SetWrapText method, thus increasing the height of the bar to accommodate the text. Without wrapping enabled, the text is truncated with an ellipsis.

Bar text is displayed in a tool-tip if truncated

If text is too long to fit in the message bar, and you have not set wrapping, then the text is right-truncated with an ellipsis (...), in which case hovering the mouse over the bar will display the entire text in a tool-tip. This can be used where text is likely to be too long to fit, but you do not want the height of the bar to be increased.

The bar background and text may be set to any colour

By default, the bar uses the system tool-tip background colour for its background, and the system tool-tip text colour for the text. These, along with the highlight colours (see below), may be overridden by specifying new colours to the SetColours method. Specifying any colour as CLR_DEFAULT causes it to be used as the default colour.

Bars may be set to 'light up' on mouse-over

You can make the bar 'light up' when the user moves their mouse over it by calling the SetHighlightOnMouseOver method. The highlight background and text colours default to the system highlight colours, but may be set by calling the SetColours method (see above).

The bar can be set to resize its parent to make room

Normally, attaching a bar to a control will resize the control's client area to make room for the bar, while leaving the control's window size as it was. While this is probably ideal for most controls, there are times when the opposite is required, for instance, adding a bar to the top of a dialog. By calling the SetResize method with TRUE, the bar will resize the window to enable the bar to fit while leaving the size of the window's client area as it was.

Custom menus may be invoked

By default, clicking or right-clicking on the message bar will display a menu offering the user one option, which is to hide the bar. By specifying a callback function, you may intercept this behaviour and supply your own menu, or carry out any other action, or allow the default behaviour. An example of such a callback function is included in the demo application, in the CMBEdit class which subclasses the edit control (note though that it is not necessary to sub-class a control in order to provide a callback function).

Reference

Functions

The public member functions of the CCtrlMessageBar class are as follows:

  • CCtrlMessageBar();
  • Standard empty constructor.

  • virtual ~CCtrlMessageBar();
  • Standard virtual destructor.

  • BOOL Attach(CWnd* pCtrl);
  • Used to attach the message bar to the control specified by pCtrl. Returns TRUE is successful, else FALSE.

  • BOOL Attach(CWnd& ctrl)
  • Used to attach the message bar to the control specified by ctrl. Returns TRUE is successful, else FALSE.

  • BOOL Attach(CWnd* pDlg, UINT nID);
  • Used to attach the message bar to the control specified by nID on the dialog specified by pDlg. Returns TRUE is successful, else FALSE.

  • CWnd* Detach();
  • Detaches the message bar from the control. Returns the control to which the message had been attached.

  • CWnd* GetCtrl() const
  • Returns the controls to which the message bar is attached.

  • BOOL IsAttached() const
  • Returns whether the message bar is currently attached to a control.

  • void SetImageList(CImageList* piml);
  • Sets the image list containing the images to be used by the message bar.

  • virtual void SetText(LPCTSTR lpszText, UINT nImage = -1, BOOL bShow = TRUE);
  • Sets the current text, and optionally the image index, for the message bar. If nImage is -1, then no image is displayed. The bShow parameter determines whether the message bar is shown immediately.

  • virtual CString GetText() const;
  • Returns the current message bar text.

  • virtual void Show(BOOL bShow = TRUE);
  • Shows or hides the message bar.

  • virtual BOOL IsShown() const;
  • Returns whether the message bar is currently shown.

  • void SetImage(UINT nImage, BOOL bShow = TRUE);
  • Specifies the index of the image in the image list to display on the message bar.

  • UINT GetImage() const;
  • Returns the index of the image currently shown on the message bar.

  • CRect GetRect(BOOL bDrawing = FALSE) const;
  • Returns the size and position of the message bar in window co-ordinates.

  • CRect GetCloseButtonRect(CRect& rc) const;
  • Returns the size and position of the message bar's close button.

  • UINT GetMessageHeight() const;
  • Returns the height, in pixels, of the message bar.

  • void SetCloseButton(BOOL bShow = TRUE);
  • Sets whether to show a close button on the message bar.

  • BOOL GetCloseButton() const
  • Returns whether a close button is shown on the message bar.

  • void SetWrapText(BOOL bWrap = TRUE)
  • Sets whether the message bar text should be wrapped, if too long, to fit in the width of the bar. If text is not wrapped, and it is too long, then text is truncated with an ellipsis (...).

  • BOOL GetWrapText() const
  • Returns whether text will wrap if too long to fit in the width of the bar.

  • void SetHighlightOnMouseOver(BOOL bHighlight = TRUE)
  • Sets whether the bar should 'light up' when the user's mouse moves over it.

  • BOOL GetHighlightOnMouseOver() const
  • Returns whether the control is set to 'light up' when the user's mouse moves over it.

  • void SetColours(COLORREF crBackgroundNormal = CLR_DEFAULT, COLORREF crTextNormal = CLR_DEFAULT, COLORREF crBackgroundHilite = CLR_DEFAULT, COLORREF crTextHilite = CLR_DEFAULT);
  • Sets colours to use for the various aspects of the message bar. Specifying CLR_DEFAULT for any of the colours causes the bar to use its own defaults.

  • void GetColours(COLORREF& crBackgroundNormal, COLORREF& crTextNormal, COLORREF& crBackgroundHilite, COLORREF& crTextHilite) const;
  • Used to get the current colours used for the various aspects of the message bar.

  • void SetResize(BOOL bResize = TRUE)
  • Specifies whether the window hosting the message bar should be resized to accommodate the message bar. The normal behaviour is to reduce the window's client area to make room for the message bar while leaving the window's size and position untouched. This option is useful when adding a message bar to a dialog or other window, where the client area should not be resized, but the overall window size should be increased.

  • BOOL GetResize() const
  • Returns whether the message bar's host window will be resized to accommodate the message bar.

  • static CCtrlMessageBar* GetMessageBarCtrl(CWnd* pCtrl);
  • Returns a pointer to the CCtrlMessageBar currently attached to the specified Windows control.

  • void SetShowMenuCallback(PFNSHOWMENUCALLBACK pfnShowMenuCallback)
  • Sets a callback function to display a context menu. See the PFNSHOWMENUCALLBACK type documentation below, for details.

Types

  • typedef BOOL (*PFNSHOWMENUCALLBACK)(CCtrlMessageBar* pBar, CWnd* pCtrl, UINT nHitTest, CPoint point);
  • The type of the callback function used to display a context menu. The callback function is called when the user left- or right-clicks on the message bar.

    The pBar parameter is the message bar clicked on. The pCtrl parameter is the control hosting the message bar. nHitTest is the hit-test code, which specifies where the user clicked, and will be one of HTMESSAGEBAR to indicate the body of the bar, or HTMESSAGEBARCLOSE to indicate the close button. The point parameter specifies the user's mouse position at the time of click, in window co-ordinates.

    The function may show - and act on - a context menu, or may choose to simply allow default handling. Return FALSE to perform default handling, else TRUE.

Acknowledgements and References

History

Version 1.0 - 23 Oct 2008

  • Added additional information to article text.

Version 1.0 - 08 Oct 2008

  • First version.

License

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