Click here to Skip to main content
15,885,998 members
Articles / Desktop Programming / MFC

Message Balloons

,
Rate me:
Please Sign up or sign in to vote.
4.84/5 (11 votes)
1 Apr 2012CPOL4 min read 237.7K   7.2K   97  
Message Balloons as opposed to Message Boxes
/*******************************************************************************
File:        BalloonTip.cpp

Description: This file contains the module for creating a a balloon tip which can
             be shown anywhere on a parent window
             

Created: Nov 1, 2001
Author:  Prateek Kaul
e-mail:  kaulpr@yahoo.com

Compiler with version number : Visual C++ 6.0


Copyright (c) 2001, Prateek Kaul
All rights Reserved.

The copyright to the computer program(s) herein is the property of Prateek Kaul
The program(s) may be used and/or copied only with the written permission of 
Prateek Kaul or in accordance with the terms and conditions stipulated
in the agreement/contract under which the program(s) have been supplied.
********************************************************************************/

#include "stdafx.h"
#include "BalloonTip.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif



/*----------------------------------------------------------------------------
   Message map
----------------------------------------------------------------------------*/

BEGIN_MESSAGE_MAP(CBalloonTip, CFrameWnd)
	//{{AFX_MSG_MAP(CBalloonTip)
	ON_WM_TIMER()
	ON_WM_LBUTTONDOWN()
	ON_WM_RBUTTONDOWN()
	ON_WM_CREATE()
	ON_WM_PAINT()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


/*-----------------------------------------------------------------------------
 Function : CBalloonTip::CBalloonTip()

 Created: Nov 1, 2001
 Author:  Prateek Kaul
 e-mail:  kaulpr@yahoo.com

 Abstract : Constructor

 Parameters : 
    1. strMessage -> Message to be shown in the balloon
    2. lf         -> LOGFONT structure from which the the message font
                     will be created.
    3. bBalloonUp -> Is the balloon up or upside down?
    
 Return Value : none

 Exceptions : none

 Revisions : none
----------------------------------------------------------------------------*/

CBalloonTip::CBalloonTip(CString strMessage, LOGFONT lf, BOOL bBalloonUp)
{
    m_strMessage       = strMessage;
    m_bBalloonUp       = bBalloonUp;

    VERIFY(m_fontBalloonText.CreateFontIndirect(&lf));
}



/*-----------------------------------------------------------------------------
 Function : CBalloonTip::~CBalloonTip()

 Created: Nov 1, 2001
 Author:  Prateek Kaul
 e-mail:  kaulpr@yahoo.com

 Abstract : Destructor

 Parameters : none
    
 Return Value : none

 Exceptions : none

 Revisions : none
----------------------------------------------------------------------------*/

CBalloonTip::~CBalloonTip()
{
}




/*-----------------------------------------------------------------------------
 Function : CBalloonTip::Show()

 Created: Nov 1, 2001
 Author:  Prateek Kaul
 e-mail:  kaulpr@yahoo.com

 Abstract : Creates the CBalloonTip on the heap, forces heap creation

 Parameters : 
    1. pt -> Point of the balloon tip
    2. size -> Size of the window(width and height)
    3. strMessage -> Message to be shown in the balloon
    4. nSecs -> Seconds for which the balloon will be shown
    5. lf -> LOGFONT structure from which the the message font
             will be created.
    6. bBalloonUp -> Is balloon up or upside down?

 Return Value : void

 Exceptions : none

 Revisions : none
----------------------------------------------------------------------------*/

CBalloonTip* CBalloonTip::Show(CPoint pt, CSize size, CString strMessage, LOGFONT lf, UINT nSecs, BOOL bBalloonUp)
{
    CBalloonTip* pBalloonTip = new CBalloonTip(strMessage, lf, bBalloonUp);
    
    UINT nRectLeft;
	UINT nRectRight;
	UINT nRectTop;  
	UINT nRectBottom;
	
    // Rectangle co-ordinates w.r.t balloon tip point
	// Balloon tip at CPoint pt shold remain there without change in window size
    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);
    }
        
	pBalloonTip->Create(CRect(nRectLeft, nRectTop, nRectRight, nRectBottom));    
    pBalloonTip->MakeVisisble(nSecs);

    return pBalloonTip;
}





/*-----------------------------------------------------------------------------
 Function : CBalloonTip::MakeVisible()

 Created: Nov 1, 2001
 Author:  Prateek Kaul
 e-mail:  kaulpr@yahoo.com

 Abstract : Shows the balloon and sets the timer for it's eventual destruction.

 Parameters : 
    1. nSecs -> Seconds for the balloon to be shown
    
 Return Value : none

 Exceptions : none

 Revisions : none
----------------------------------------------------------------------------*/

void CBalloonTip::MakeVisisble(UINT nSecs)
{
    ASSERT(nSecs > 0);

    SetTimer(ID_TIMER, (nSecs * 1000), NULL);
        
    CRect rect;
    GetWindowRect(&rect);

    // Caption bar height to offeset when the balloon is shown
    int nCaptionBarSize = ::GetSystemMetrics(SM_CYCAPTION);
    int nVerticalBorderSize = ::GetSystemMetrics(SM_CYSIZEFRAME);

    if(m_bBalloonUp)
    {
        // Account for the missing title bar and border thickness in the 3rd parameter
        // as the balloon shifts up by the height of title bar and window tickness
        SetWindowPos(
            &wndTopMost,
            m_rectWindow.left, 
            (m_rectWindow.top + nCaptionBarSize + (2 * nVerticalBorderSize)),
            m_rectWindow.right,
            m_rectWindow.bottom, 
            SWP_SHOWWINDOW | SWP_NOACTIVATE
        );
    }
    else
    {
        // Account for the missing title bar and border thickness in the 3rd parameter
        // as the balloon shifts up by the height of window tickness.
        SetWindowPos(
            &wndTopMost, 
            m_rectWindow.left,
            m_rectWindow.top - nVerticalBorderSize,
            m_rectWindow.right, 
            m_rectWindow.bottom,
            SWP_SHOWWINDOW | SWP_NOACTIVATE
        );
    }
}




/*-----------------------------------------------------------------------------
 Function : CBalloonTip::OnTimer()

 Created: Nov 1, 2001
 Author:  Prateek Kaul
 e-mail:  kaulpr@yahoo.com

 Abstract : Gets called by MFC for an WM_TIMER message

 Parameters : 
        1. nIDEvent -> Timer ID    

 Return Value : void

 Exceptions : none

 Revisions : none
----------------------------------------------------------------------------*/

void CBalloonTip::OnTimer(UINT nIDEvent) 
{
    KillTimer(ID_TIMER);
    DestroyWindow();
}




/*-----------------------------------------------------------------------------
 Function : CBalloonTip::OnLButtonDown()

 Created: Nov 1, 2001
 Author:  Prateek Kaul
 e-mail:  kaulpr@yahoo.com

 Abstract : Gets called by MFC for an WM_LBUTTONDOWN message

 Parameters : 
        See MFC documentation

 Return Value : void

 Exceptions : none

 Revisions : none
----------------------------------------------------------------------------*/

void CBalloonTip::OnLButtonDown(UINT nFlags, CPoint point) 
{
   	KillTimer(ID_TIMER);
    DestroyWindow();
}




/*-----------------------------------------------------------------------------
 Function : CBalloonTip::OnRButtonDown()

 Created: Nov 1, 2001
 Author:  Prateek Kaul
 e-mail:  kaulpr@yahoo.com

 Abstract : Gets called by MFC for an WM_RBUTTONDOWN message

 Parameters : 
        See MFC documentation

 Return Value : void

 Exceptions : none

 Revisions : none
----------------------------------------------------------------------------*/

void CBalloonTip::OnRButtonDown(UINT nFlags, CPoint point) 
{
    KillTimer(ID_TIMER);
    DestroyWindow();
}




/*-----------------------------------------------------------------------------
 Function : CBalloonTip::OnCreate()

 Created: Nov 1, 2001
 Author:  Prateek Kaul
 e-mail:  kaulpr@yahoo.com

 Abstract : Gets called by MFC for an WM_CREATE message

 Parameters : 
        See MFC documentation

 Return Value : int

 Exceptions : none

 Revisions : none
----------------------------------------------------------------------------*/

int CBalloonTip::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
    {
        return -1;
    }
	
    // Remove caption and thick frame for proper shading
    ModifyStyle(WS_CAPTION | WS_THICKFRAME, 0); 

    CRect t_Rect;
	GetClientRect(&t_Rect);  // Get the client rectangle to set the balloon region

    if (m_bBalloonUp)
    {
        // Calculation of Text window, where to write text in the balloon
        m_rectText.left   = t_Rect.Width() * 0.10; 
        m_rectText.right  = t_Rect.Width() * 0.90;
        m_rectText.top    = t_Rect.Height() * 0.10; 
        m_rectText.bottom = t_Rect.Height()* 0.70; 
            	
        // Create an elliptical region out of the client rectangle
	    m_rgnRoundRect.CreateRoundRectRgn(
            t_Rect.left, 
            t_Rect.top, 
            t_Rect.right,
            t_Rect.bottom - (t_Rect.Height() * 0.25), 
            abs(t_Rect.left - t_Rect.right) * 0.18,
            t_Rect.Height() * 0.25
        );
   
        // Start the process of creating the balloon tip
	    CPoint ptTri[4];
	    ptTri[0].x = (t_Rect.left) + (t_Rect.Width() * 0.93);
	    ptTri[0].y = (t_Rect.bottom) - (t_Rect.Height() * 0.40);
    
	    ptTri[1].x = (t_Rect.left) + (t_Rect.Width() * 0.65);
	    ptTri[1].y = t_Rect.bottom;

	    ptTri[2].x = (t_Rect.left) + (t_Rect.Width() * 0.70);
	    ptTri[2].y = (t_Rect.bottom) - (t_Rect.Height() * 0.40);
   
	    ptTri[3].x = (t_Rect.left) + (t_Rect.Width() * 0.93);
	    ptTri[3].y = (t_Rect.bottom) - (t_Rect.Height() * 0.40);
   
	    m_rgnTip.CreatePolygonRgn(ptTri, 3, ALTERNATE);
    }
    else
    {
        // Calculation of Text window, where to write text in the balloon
        m_rectText.left   = t_Rect.Width() * 0.10;
        m_rectText.right  = t_Rect.Width() * 0.90;
        m_rectText.top    = t_Rect.Height() * 0.30;
        m_rectText.bottom = t_Rect.Height() * 0.90;
        
        // Create an elliptical region out of the client rectangle
	    m_rgnRoundRect.CreateRoundRectRgn(
            t_Rect.left,
            t_Rect.bottom - (t_Rect.Height() * 0.75), 
            t_Rect.right, 
            t_Rect.bottom, 
            abs(t_Rect.left - t_Rect.right) * 0.18,
            t_Rect.Height() * 0.25
        );

        // Start the process of creating the balloon tip
	    CPoint ptTri[4];
	    ptTri[0].x = (t_Rect.left) + (t_Rect.Width() * 0.07);
	    ptTri[0].y = (t_Rect.Height() * 0.40);
            
	    ptTri[1].x = (t_Rect.left) + (t_Rect.Width() * 0.35);
	    ptTri[1].y = t_Rect.bottom - t_Rect.Height();

	    ptTri[2].x = (t_Rect.left) + (t_Rect.Width() * 0.30);
	    ptTri[2].y = t_Rect.Height() * 0.40;
           
	    ptTri[3].x = (t_Rect.left) + (t_Rect.Width() * 0.07);
	    ptTri[3].y = t_Rect.Height() * 0.40;
           
	    m_rgnTip.CreatePolygonRgn(ptTri, 3, ALTERNATE);
    }
    
    // Create the combined region with ellipse and tip
	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);
	
    if (iRetComb == ERROR)
	{
        ::AfxMessageBox( "ERROR in Combining Region" );
		return -1;
	}
   
    SetWindowRgn(rgnComb.operator HRGN(), TRUE);
	
	return 0;
}




/*-----------------------------------------------------------------------------
 Function : CBalloonTip::OnPaint()

 Created: Nov 1, 2001
 Author:  Prateek Kaul
 e-mail:  kaulpr@yahoo.com

 Abstract : Gets called by MFC for a WM_PAINT message

 Parameters : 
        See MFC documentation

 Return Value : void

 Exceptions : none

 Revisions : none
----------------------------------------------------------------------------*/

void CBalloonTip::OnPaint() 
{
	CPaintDC dc(this); // device context for painting

    CRect t_Rect;
    GetClientRect(&t_Rect);

    // Get the total balloon, inclding all cut out regions
	CRgn rgnComb;	
    rgnComb.CreateRectRgn(t_Rect.left, t_Rect.top, t_Rect.right, t_Rect.bottom);
   
    // Create a balloon tip from this total region
    int iRetComb = rgnComb.CombineRgn(&m_rgnTip, &m_rgnRoundRect, RGN_OR );
    if (iRetComb == ERROR)
	{
        ::AfxMessageBox( "ERROR in Combining Region" );
        return;
	}

	CBrush brOutlineBrush;
    brOutlineBrush.CreateSolidBrush(RGB(0, 0, 0)); // blue
   
    CBrush brFillBrush;
    brFillBrush.CreateSolidBrush(RGB(249, 254, 188)); // light yellow
   
   
    dc.FillRgn(&rgnComb, &brFillBrush);  // Fill the balloon
    dc.FrameRgn(&rgnComb, &brOutlineBrush, 2, 1); // Outline the balloon

    int nBkMode          = dc.SetBkMode(TRANSPARENT);
    COLORREF clrPrevious =  dc.SetTextColor(RGB(255, 0, 0));
    CFont *pFont = dc.SelectObject(&m_fontBalloonText);
   
    CSize czTextWidth = dc.GetTextExtent(m_strMessage);
   
    if (czTextWidth.cx < m_rectText.Width())
    {
       dc.DrawText(m_strMessage, m_rectText, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
    }
     
    else
    {
        dc.DrawText(m_strMessage, m_rectText, DT_CENTER | DT_WORDBREAK);
    }
    
    // Restore the DC to its oroginal state
    dc.SelectObject(pFont);
    dc.SetBkColor(nBkMode);
    dc.SetTextColor(clrPrevious);
}




/*-----------------------------------------------------------------------------
 Function : CBalloonTip::PreCreateWindow(CREATESTRUCT& cs)

 Created: Dec 07, 2001
 Author:  Prateek Kaul
 e-mail:  kaulpr@yahoo.com

 Abstract : Called by MFC when a before WM_CREATE message is received by the
            window.

            We override this function so that the window so created is not
            visible in the Taskbar. We make this window the child of an
            invisible parent m_wndInvisibleParent.

 Parameters : Look in MFC documentation

 Return Value : BOOL

 Exceptions : none

 Revisions : none
----------------------------------------------------------------------------*/

BOOL CBalloonTip::PreCreateWindow(CREATESTRUCT& cs)
{
	if (!CWnd::PreCreateWindow(cs))
    {
		return FALSE;
    }

 	// Create invisible parent window
 	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
                      );

        if (bError == FALSE)
        {
			return FALSE;
        }
 	}

    // Set the invisible window as the parent of "this" window
	cs.hwndParent = m_wndInvisibleParent.m_hWnd;

	return TRUE;
}




/*-----------------------------------------------------------------------------
 Function : CBalloonTip::Create()

 Created: Dec 07, 2001
 Author:  Prateek Kaul
 e-mail:  kaulpr@yahoo.com

 Abstract : Called by the static CBalloonTip to create a Windows(R) window 

 Parameters : rect-> a rectangle in screen co ordinates where the balloon
              will be displayed.

 Return Value : BOOL

 Exceptions : none

 Revisions : none
----------------------------------------------------------------------------*/

BOOL CBalloonTip::Create(CRect rect)
{
    m_rectWindow = rect;

    PCSTR pstrOwnerClass = ::AfxRegisterWndClass(0);
    BOOL bResult = CFrameWnd::Create(pstrOwnerClass, NULL, WS_OVERLAPPED, m_rectWindow);
    
    return bResult;
}





/*-----------------------------------------------------------------------------
 Function : CBalloonTip::Hide()

 Created: Dec 08, 2001
 Author:  Prateek Kaul
 e-mail:  kaulpr@yahoo.com

 Abstract : Provided to hide a balloon before it self destructs. If it is 
            already hidden, it will have no effect.
            Even if the balloon is invisible it wil self destruct when the
            Timer(WM_TIMER) ticks.

 Parameters : None

 Return Value : void

 Exceptions : none

 Revisions : none
----------------------------------------------------------------------------*/

void CBalloonTip::Hide()
{
    ShowWindow(SW_HIDE);
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

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


Written By
Web Developer
India India
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Written By
Web Developer
Canada Canada
I have been programming for the past 5 years or so. I started out with C for about 1 year, then took a break and ended up doing Access and VB for a short while. It was then followed by more C, a bit of Java and database development in Oracle and SQL Server and web development in ASP, until I arrived in the C++ and MS windows world. I have been working with MFC for the past 2-3 years and have some COM and Win32 API experience as well. I have recently begun the journey of .NET as well, trying to keep up with the latest hype.

Comments and Discussions