Message Balloons



Click here for larger image

Environment: VC++ 6.0, MFC, Windows 2000/XP/9x/ME/NT

Introduction

There are times when one would like to display messages in an non-obtrusive way. Message Balloons are one of the new ways. Message Balloons are taking precedence over message boxes for small display messages as they even prevent the user from clicking an OK and still get the message across. These kind of Message Balloons are becoming a part of standard user interface with MSN explorer and Windows XP. Still no library has been provided for making these balloons. Hence this attempt.

How to use the class provided ?

Include the following two files in your project:
  • BalloonTip.h
  • BalloonTip.cpp
There are two interfaces to create and show the message balloons.
  • CBalloonTip::Show()
  • CBalloonTip::Hide()


CBalloonTip::Show()-: This is a pseudo constructor because we want to force heap creation of the balloon, so that it remains in the memory even after it has been called. It will be automatically destroyed when a it receives a WM_TIMER message which is set in the CBalloon::MakeVisible(). The constructor for CBalloonTip is protected, hence this helps in forcing heap creation.The following code shows how to create a Message Balloon and show it.
LOGFONT lf;
::ZeroMemory (&lf, sizeof (lf));
lf.lfHeight = 16;
lf.lfWeight = FW_BOLD;
lf.lfUnderline = FALSE;
::strcpy (lf.lfFaceName, _T("Arial"));

CBalloonTip::Show(
    CPoint(200, 200),  // Point on the screen where 
                       // the tip will be shown
    CSize(250, 100),   // Size of the total rectangle 
                       // encompassing the balloon 
    _T("Please enter a password !!"), // Message to be shown
                                      // in the balloon
    lf,     // LOGFONT structure for 
            // font properties 
    5,      // Time in seconds to show the balloon
    FALSE   // TRUE  == Balloon is up(Balloon Tip is down) 
            // FALSE ==  Balloon is down(Balloon Tip is up)
);


CBalloonTip::Hide()-: This is for destroying the Balloon for any particular condition that may arise before it is automatically destroyed in the CBalloonTip::OnTimer(). Either way if CBalloonTip::Hide() is not called the Balloon is destroyed in CBalloonTip::OnTimer(). So the caller(user of this class) does not need to worry about the memory cleanup.

Class Design Details

CBalloonTip is derived from CFrameWnd. The balloon is created from the combination of two regions, one is a polygon region to show the the Balloon Tip and the other is a Round Rectangle region. This is done in the CBalloonTip::OnCreate().
int CBalloonTip::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
    //..........Some code
    //...................

    CRgn rgnComb;
    
    rgnComb.CreateRectRgn( t_Rect.left, 
                           t_Rect.top,
                           t_Rect.right,
                           t_Rect.bottom);

    int iRetComb = rgnComb.CombineRgn(&m_rgnTip,
                                      &m_rgnRoundRect,
                                      RGN_OR);
}
The m_rgnTip and m_rgnRoundRect are created with different calculations depending upon whether the balloon tip is down or up. The visible window or balloon region is finally set using SetWindowRgn(rgnComb.operator HRGN(), TRUE) in the CBalloonTip::OnCreate().
The Balloon window is not shown up in the taskbar by making the Balloon a child of an invisible parent in CBalloonTip::PreCreateWindow() This parent window is a member variable (CBalloon::m_wndInvisibleParent) of the class itself and is destroyed automatically when the Balloon is destroyed. So the non-appearance of the Balloon window in the task bar is taken care of automatically.

BOOL CBalloonTip::PreCreateWindow(CREATESTRUCT& cs)
{
    //...............Some code
    //........................

    if (!::IsWindow(m_wndInvisibleParent.m_hWnd))
    {
        // Try creating the invisible parent window
        PCSTR pstrOwnerClass = ::AfxRegisterWndClass(0);
       
        BOOL bError = m_wndInvisibleParent.CreateEx(
                          0,
                          pstrOwnerClass, 
                          _T(""), 
                          WS_POPUP,
                          0,
                          0,
                          0,
                          0,
                          NULL,
                          0
                      );
    }
}

Window Creation

The balloon is created with respect from the point where it is supposed to be displayed. So the calculation of balloon rectangle has to be recalculated w.r.t the point at which it is to be shown. Different calculations have to be done if the Balloon tip is down or up. This is done in CBalloontip::Show() as shown below,
CBalloonTip* CBalloonTip::Show( CPoint pt,
                                CSize size,
                                CString strMessage,
                                LOGFONT lf,
                                UINT nSecs,
                                BOOL bBalloonUp)
{
    //.........Some code
    //..................

    if (bBalloonUp)
    {
        nRectLeft   = pt.x - (size.cx * 0.65);
        nRectRight  = pt.x + (size.cx * 0.35);
        nRectTop    = pt.y - size.cy;
        nRectBottom = pt.y;
    }
    else
    {
        nRectLeft   = pt.x - (size.cx * 0.35);
        nRectRight  = pt.x + (size.cx * 0.65);
        nRectTop    = pt.y;
        nRectBottom = pt.y + (size.cy);
    }
}
The actual Windows. window balloon is created in CBalloonTip::Show() using
pBalloonTip->Create( CRect( nRectLeft,
                            nRectTop,
                            nRectRight,
                            nRectBottom));
The CRect passed in the above function will represent the actual position of the balloon in screen co-ordinates. The timer for the Balloon destruction is set in the next line in CBalloonTip::Show()
pBalloonTip->MakeVisisble(nSecs);
  • Only one instance of the Balloon is allowed to created at a time using the static variable CBalloonTip::nBalloonInstances
  • Overview of the demo project

    Sample Image

  • Just click the "OK" button without entering anything in the the edit boxes.
  • Compatibility

    Tested using VC++ 6 with MFC on Windows 2000. Should work fine on other Windows OSs(95/98/NT/ME/XP) also, as it uses no OS specific code.

    Conclusion

    I hope that this contribution will make some improvement in the user interface code of your forthcoming programs!!! Any suggestions, improvements or bugs detected are welcome. Enjoy.....

    Downloads

    Download demo project - 15 Kb
    Download source - 6 Kb


    Comments

    • Use CToolTipCtrl, this doesn't work.

      Posted by Legacy on 04/12/2002 12:00am

      Originally posted by: Paul Richards

      Don't even bother with this, CToolTipCtrl supports multiline, and delay times.

      Search this site for CToolTipCtrl for more info.

      Reply
    • nice idea, Doesnt Work Feb02

      Posted by Legacy on 02/20/2002 12:00am

      Originally posted by: cts

      No Balloons in Wind98 VC6

      Reply
    • The Reason of balloon can't see!

      Posted by Legacy on 12/14/2001 12:00am

      Originally posted by: DaFu Chen

      It has a bug in the CBalloonDialogDlg::OnOK()

      pEditName->GetLine(0, szName);
      pEditPassWd->GetLine(0, szPassWd);

      The GetLine() fuction has two versions :

      int GetLine( int nIndex, LPTSTR lpszBuffer ) const;
      int GetLine( int nIndex, LPTSTR lpszBuffer, int MaxLength ) const;

      For two parameters version, the first word of the buffer must specify the maximum number of bytes that can be copied to the buffer.

      So, change them to three parameters version like this:

      pEditName->GetLine(0, szName,40);
      pEditPassWd->GetLine(0, szPassWd,40);

      Now if you have not input the user name or password and press the "OK" button, you can see the balloons

      Good luck

      Reply
    • No Baloon seen on Win98

      Posted by Legacy on 12/13/2001 12:00am

      Originally posted by: Hari Ramakrishnan P

      I tried it for Win98, i cann't see any baloon.

      Reply
    • Good one....

      Posted by Legacy on 12/12/2001 12:00am

      Originally posted by: Srinidhi Rao

      Hey Prateek,
      
      

      Thats a good one. Indeed it would be a different way of communicating messages. Thanks for good work.

      It seems there is a problem with the Demo Zip. Check it out. Yeah, you can always write a simple demo app tp get it running... :-)

      Thanks
      Srini...

      Reply
    • Cool.. but..

      Posted by Legacy on 12/11/2001 12:00am

      Originally posted by: soichi

      As far as I see on the article, it looks really nice. But the zip files for the project you attached to the article contains CRC error on the resouce.rc! :) It will be nice if you could fix this problem.

      Thanks!

      Reply
    Leave a Comment
    • Your email address will not be published. All fields are required.

    Top White Papers and Webcasts

    • As all sorts of data becomes available for storage, analysis and retrieval - so called 'Big Data' - there are potentially huge benefits, but equally huge challenges...
    • The agile organization needs knowledge to act on, quickly and effectively. Though many organizations are clamouring for "Big Data", not nearly as many know what to do with it...
    • Cloud-based integration solutions can be confusing. Adding to the confusion are the multiple ways IT departments can deliver such integration...

    Most Popular Programming Stories

    More for Developers

    RSS Feeds

    Thanks for your registration, follow us on our social networks to keep up-to-date