Introduction
When using Microsoft® Outlook®, we come across the mail notification window, which appears slowly and starts disappearing. It displays a summary of a mail, including the sender's name etc. This articles describes how to build that kind of a window using ATL.
Background
I recently came across an article by Nick Wälti. But did not find any C++ code for achieving the same. So I tried to achieve something similar using ATL.
Using the code
There are three classes:
CATLNotifyDialog
represents the main UI.
CNotifyWnd
represents the notification window.
CBmpButton
represents the bitmap button class, used as the 'Close' button.
typedef CWinTraits <WS_CLIPCHILDREN | WS_POPUP |WS_VISIBLE ,0 > CNotificationWinTraits;
class CNotifyWnd : public CWindowImpl<CNotifyWnd,CWindow,CNotificationWinTraits>
{
.
.
CBmpButton* m_pButton;
public:
DECLARE_WND_CLASS("CNotifyWnd")
BEGIN_MSG_MAP(CNotifier)
MESSAGE_HANDLER(WM_CREATE, OnCreate)
.
.
.
REFLECT_NOTIFICATIONS()
END_MSG_MAP()
void CreateNotifyWindow();
private:
LRESULT ChangeOpacity(BYTE iFactor);
};
The macro REFLECT_NOTIFICATIONS
is declared to send messages to child windows. In this case, the button window is the child. In the OnCreate
function, modify the extended style of the window by adding WS_EX_LAYERED
. More information on Layered Windows can found in the MSDN.
if ( ModifyStyleEx(0,WS_EX_LAYERED ))
{
SetTimer(TIMER_ID ,30);
m_bTimerActive=TRUE;
}
The ChangeOpacity
function of this class will bring a translucent effect to the window.
LRESULT CNotifyWnd::ChangeOpacity(BYTE iFactor)
{
typedef DWORD (WINAPI *pSetLayeredWindowAttributes)(HWND, DWORD, BYTE, DWORD);
pSetLayeredWindowAttributes SetLayeredWindowAttributes;
HMODULE hDLL = LoadLibrary ("user32");
if (hDLL )
{
SetLayeredWindowAttributes = (pSetLayeredWindowAttributes)
GetProcAddress(hDLL,"SetLayeredWindowAttributes");
ATLASSERT(SetLayeredWindowAttributes );
BOOL bRes=SetLayeredWindowAttributes(m_hWnd,RGB(255,255,255),
iFactor, LWA_COLORKEY | LWA_ALPHA);
FreeLibrary(hDLL);
}
else
{
ATLASSERT(0);
}
return 0;
}
The class CBmpButton
is a button class. It uses three bitmaps to represent its states, i.e., normal, mouse move, and pressed. I could not get better bitmaps for this application, but a more artistic person can really make it beautiful.
class CBmpButton :public CWindowImpl<CBmpButton>
{
UINT m_BitmapId[3];
UINT m_nCurrentBmp;
public:
DECLARE_WND_SUPERCLASS( _T("BitmapButton"), _T("Button") )
BEGIN_MSG_MAP(CBmpButton)
.
.
.
MESSAGE_HANDLER(OCM_DRAWITEM, OnDrawItem)
DEFAULT_REFLECTION_HANDLER()
END_MSG_MAP()
private:
};
Here is an important function of the above class:
LRESULT CBmpButton::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
ModifyStyle(0,BS_OWNERDRAW);
return 1;
}
Functions like CBmpButton::OnLButtonDown
, CBmpButton::OnLButtonUP
, CBmpButton::OnMouseLeave
, and CBmpButton::OnMouseLeave
will set m_nCurrentBmp
with the appropriate bitmap.
TrackMouseEvent(&stMouseEvent);
The code assumes that the taskbar is always at the bottom (does not consider other cases).
Points of Interest
It does not use MFC (that's lighter!).
History