See recent updates to the source, or download older versions of this source below:
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 other method to destroy the Balloon before the timer ticks is to call the static function CBalloon::Hide()
.
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), CSize(250, 100), _T("Please enter a password !!"), lf, 5, FALSE );
See the updates section to see more about this function.
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.
See the updates section to see more about this function.
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)
{
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)
{
if (!::IsWindow(m_wndInvisibleParent.m_hWnd))
{
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)
{
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
Just try clicking 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.
The following changes to the code in the updated version have been made by R. Khalili:
- The OnPaint and Show methods have been updated to do a better job.
- The message balloon doesn't stay on top of applications as you switch between apps.
- There is more rigorous checking to prevent crashes as a result of null pointers, etc...
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...