Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

CBalloonMsg - An Easy-to-use Non-modal Balloon Alternative to AfxMessageBox

0.00/5 (No votes)
1 Apr 2008 2  
Makes it easy to use a balloon tooltip to convey hints/messages non-modally

Introduction

While working on a new app, I decided it would be nice to use balloon-style tooltips to convey simple messages to the user rather than relying on ye olde ::AfxMessageBox. It would be a less disruptive way of warning the user of minor things like editing mistakes, failing to fill in a field and so on.

I found an existing CodeProject article that seemed to be exactly what I was looking for: Balloon Help as a Non-modal Replacement for MessageBox(). On closer inspection, I decided against using this because it doesn't use Windows' own balloon tooltip. Instead, it draws its own, and at the time of writing I think it needs a small update for Vista. Surely there had to be a simpler solution that uses the real tooltip control? Well I didn't find one, so I wrote my own and it's called CBalloonMsg.

Prerequisites

Before going any further, please be aware that I coded this for use in theme-aware apps (i.e. those with a manifest requesting common controls v6) running on Vista or XP (preferably SP2). I haven't tried using it on Windows 2000, but I'm pretty sure it wouldn't look right. And don't even think about NT4 and Win9x!

Using the Code

This couldn't be much simpler:

  • Add BalloonMsg.h and BalloonMsg.cpp to your project.
  • Make sure your stdafx.h has WINVER and _WIN32_WINNT set to 0x0501 or better and make sure you've got a manifest in your *.rc2 (check out the demo!)
  • Finally, use one of the Show or ShowForCtrl static methods to display the balloon message, e.g.

    CBalloonMsg::ShowForCtrl( _T("Test Title"), _T("Test Text"),
        &my_ctrl, hIcon );

The Show/ShowForCtrl methods display the tooltip at the nominated position or over the nominated control. By default, the tooltip stays up for 10 seconds then closes automatically. It'll close earlier if there's a change in focus or if the mouse moves appreciably. You can change the "stay up" or autopop time easily (more on this later) and you can close or "pop" the balloon at any time using the RequestCloseAll() static method.

How it Works (Briefly)

When you call one of the Show methods, a separate user interface thread is created. This in turn creates its own small, transparent window around the current mouse position, then sets about processing that window's message queue. The window acts as the parent for a tooltip control, and calls CToolTipCtrl::RelayEvent to make sure that the tooltip has first bit at all relevant Windows messages. The tooltip is given a zero millisecond initial delay, so it appears as soon as it is activated. When the tooltip eventually closes, a call is made to PostQuitMessage which gets rid of the transparent parent window and ends the thread. The thread wrapper self-deletes for completeness.

That's about it. You'll find more detailed information on the inner workings in the code's comments.

Points of Interest

SafeShowMsg and BalloonsEnabled

By default, Windows allows the use of balloon tooltips. There is however a registry tweak available that prevents balloons from being displayed. It seems this is most often used to kill those often redundant and distracting tray balloons that Windows likes to present from time to time.

The tweak involves setting zero for the DWORD value EnableBalloonTips in HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced (thanks to DerMeister for reporting this!)

To get around this, the latest version of the class now includes two additional methods: BalloonsEnabled and SafeShowMsg.

BalloonsEnabled() returns TRUE if the user hasn't suppressed balloon tooltips. Following on from that, SafeShowMsg() uses balloons to display a message if they're enabled, and reverts to AfxMessageBox if the user has switched them off. The demo shows this function in action - take a look at CTTTestDlg::DoDataExchange.

Icons

You can supply your own icon to the Show calls, OR you can use Windows' built-in icons by using the special values described in the MSDN doc for TTM_SETTITLE: 1 for info, 2 for warning, 3 for error.

You can also change quite a few of the defaults for CMessageBalloon by setting new values for its static members:

s_nTimerStep Defaults to 30 milliseconds. Determines frequency of checks for balloon termination states (see History for Version 2 changes)
s_nAutoPop Time before balloon self-closes in milliseconds. Defaults to 10 seconds. Set to 0 to let the balloon stay up until closed through focus changes, user action etc.
s_nMaxTipWidth Maximum tip width in pixels. Makes the balloon use linebreaks.
s_nToolBorder The amount by which the mouse can move before the balloon pops

GetGUIThreadInfo

Finally, note the use of the handy function GetGUIThreadInfo which allows us to check the focus window in another thread.

Special Version Adapted for VC6 by Damir Valiulin

The third download at the top of the article is for a VC6 version of the demo project. It contains some minor differences from the original code, as follows:

  • Minor changes to be able to compile under VC6
  • Check for Win32 (no balloon tip there) and for registry disabling hack
  • Changes to function calls for simplification (got rid of calls with string IDs)

Many thanks to Damir for this!

History

Version 1: 6th March, 2008


Version 2: 16th March, 2008

Changed to using a tracking tooltip to counter anomalies in positioning of the balloon and its pointer when the dialog was near the edge of the screen. The use of TTF_TRACK necessitated other changes:

  • Repositioning of the balloon is now achieved via the TTM_TRACKPOSITION message rather than through the use of SetWindowPos.
  • TTM_TRACKACTIVATE is now used to activate the tooltip, rather than the MFC method Activate().
  • A timer is also created and set to fire every 30 milliseconds or so (this is configurable via s_nTimerStep above). The timer gives us a chance to spot changes in the state of windows owned by the primary thread that should bring about closure of the balloon. It also lets us (re)implement the automatic closure interval (autopop) that is used when s_nAutoPop is non-zero.

Version 3: 23rd March, 2008

  • Added SafeShowMsg and BalloonsEnabled to detect when the user has suppressed balloons via a reg tweak and fall back to AfxMessageBox.
  • Added overloads to take HWND for target control as well as CWnd*.

Version 4: 30th March, 2008

  • Added a VC6 version, kindly adapted by Damir Valiulin.

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