任务栏右下角弹出气球式消息

 

在任务栏右下角弹出气球式消息,指定时间后消失:

void CTrayDemoDlg::ShowBalloon(CString szText)

{

CTBalloon * pballoon = new CTBalloon(150,100);

pballoon->SetText(szText);//文字

pballoon->SetLifeTime(4); //停留时间(秒)

pballoon->CreateAndShow();

}

 

TBalloon.h

 

代码
TBalloon.h

#if !defined(AFX_TBALLOON_H__8363E22A_9845_4086_B3A0_40117DCFDB1F__INCLUDED_)
#define AFX_TBALLOON_H__8363E22A_9845_4086_B3A0_40117DCFDB1F__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

///////////////////////////////////////////////////////////////////////////////
// class CTBalloon

/////////////////////////////////////////////////////////////////////////////
// CTBalloon window
#include "Gradient.h"

class CTBalloon : public CWnd
{
// Construction
public:
CTBalloon(UINT nWidth, UINT nHeight);
BOOL CreateAndShow();
void SetText(CString str);
void SetLifeTime(UINT secs);


static UINT m_sActiveCount;

// Attributes
private:
CRect m_current_rect;
CRect m_screen_rect;
UINT m_nWidth;
UINT m_nHeight;
UINT m_totaltime;
UINT m_lifetime;
BOOL m_dir;
CString m_text;
CGradient m_grad;

// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CTBalloon)
public:
protected:
virtual void PostNcDestroy();
//}}AFX_VIRTUAL

// Implementation
public:
virtual ~CTBalloon();

// Generated message map functions
protected:
//{{AFX_MSG(CTBalloon)
afx_msg void OnPaint();
afx_msg
void OnTimer(UINT nIDEvent);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_TBALLOON_H__8363E22A_9845_4086_B3A0_40117DCFDB1F__INCLUDED_)

 

TBalloon.cpp 

 

代码
TBalloon.cpp

///////////////////////////////////////////////////////////////////////////////
// class CTBalloon


#include
"stdafx.h"
//#include "TrayBalloon.h"
#include "TBalloon.h"
#include
"Gradient.h"

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

/////////////////////////////////////////////////////////////////////////////
// CTBalloon

#define BALLOON_SHOW_TIMER 0x10
#define TIMER_MS 20
#define BALLOON_LIFETIME (3*1000)
#define STEP_SIZE 5

UINT CTBalloon::m_sActiveCount;


CTBalloon::CTBalloon(UINT nWidth, UINT nHeight): m_nWidth(nWidth), m_nHeight(nHeight)
{
SystemParametersInfo(SPI_GETWORKAREA,
0, &m_screen_rect, 0);
m_totaltime
= 0;
m_lifetime
= BALLOON_LIFETIME;
m_dir
= TRUE;
}

CTBalloon::
~CTBalloon()
{
}


BEGIN_MESSAGE_MAP(CTBalloon, CWnd)
//{{AFX_MSG_MAP(CTBalloon)
ON_WM_PAINT()
ON_WM_TIMER()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

void CTBalloon::SetText(CString str)
{
m_text
=str;
}


void CTBalloon::SetLifeTime(UINT secs)
{
m_lifetime
= secs * 1000;
}

BOOL CTBalloon::CreateAndShow()
{

const wchar_t * p = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW );

CRect rect;
rect.top
= m_screen_rect.bottom - m_nHeight;
rect.bottom
= m_screen_rect.bottom;
rect.left
= m_screen_rect.right - m_nWidth - 10 - (m_sActiveCount * 10) ;
rect.right
= m_screen_rect.right - 10 - (m_sActiveCount * 10);

DWORD dwStyle
= WS_POPUP;
DWORD dwExStyle
= WS_EX_TOOLWINDOW |WS_EX_CLIENTEDGE | WS_EX_TOPMOST | WS_EX_WINDOWEDGE ;


BOOL ret
= CreateEx(dwExStyle,p,NULL,dwStyle,rect,NULL,NULL);

m_sActiveCount
++;

m_current_rect.top
= m_current_rect.bottom = m_screen_rect.bottom;
m_current_rect.left
= rect.left;
m_current_rect.right
= rect.right;


COLORREF lightblue
= RGB(154,190,255);
COLORREF white
= RGB(255,255,255);


m_grad.SetDirection(CGradient::RTL);
m_grad.SetGradientColorsX(
3,lightblue,lightblue,white);


SetTimer(BALLOON_SHOW_TIMER,TIMER_MS,NULL);
return ret;
}

/////////////////////////////////////////////////////////////////////////////
// CTBalloon message handlers



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

CBrush br(
0xFF0000);
CRect rect(
0,0,m_current_rect.Width(),m_current_rect.Height());
m_grad.DrawLinearGradient(
&dc,rect);

dc.SelectStockObject(ANSI_VAR_FONT);
dc.SetBkMode(TRANSPARENT);
CRect temp
= rect;
UINT height
= dc.DrawText(m_text,-1,temp,DT_CENTER|DT_WORDBREAK|DT_CALCRECT);

rect.top
= (rect.Height() - height)/2;
dc.DrawText(m_text,
-1,rect,DT_CENTER|DT_WORDBREAK);

// Do not call CWnd::OnPaint() for painting messages
}


void CTBalloon::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default

m_totaltime
+= TIMER_MS;

if (m_totaltime > m_lifetime)
{
m_dir
= FALSE;
}

if (m_dir)
{
m_current_rect.top
= ((m_current_rect.top - STEP_SIZE) < (m_current_rect.bottom - (LONG)m_nHeight))? m_current_rect.bottom - m_nHeight : m_current_rect.top - STEP_SIZE;
}
else
{
m_current_rect.top
= ((m_current_rect.top + STEP_SIZE) > (m_current_rect.bottom))? m_current_rect.bottom : m_current_rect.top + STEP_SIZE;
}


MoveWindow(
&m_current_rect);

if (m_current_rect.top == m_current_rect.bottom)
{
KillTimer(BALLOON_SHOW_TIMER);
DestroyWindow();
return;
}

CWnd
* pWnd = GetFocus();
ShowWindow(SW_RESTORE);
if (pWnd)
pWnd
->SetFocus();


CWnd::OnTimer(nIDEvent);
}

void CTBalloon::PostNcDestroy()
{
// TODO: Add your specialized code here and/or call the base class

delete
this;
m_sActiveCount
--;

}

 

 Gradient.h

 

代码
Gradient.h

#if !defined(AFX_GRADIENT_H__2FB4902E_E00C_4892_AA03_60779F349F58__INCLUDED_)
#define AFX_GRADIENT_H__2FB4902E_E00C_4892_AA03_60779F349F58__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

///////////////////////////////////////////////////////////////////////////////
// class CGradient
//

#include
<afxtempl.h>

#ifndef UIBITS_API
#ifdef UIBITS_DLL
#define UIBITS_API __declspec(dllexport)
#else
#define UIBITS_API __declspec(dllimport)
#endif
#endif

struct CGradElement
{
CGradElement(COLORREF color
= 0, int length = 0){this->color = color; this->length = length;}
COLORREF color;
int length;
};

typedef CArray
<CGradElement, CGradElement&> CGradArray;

class /*UIBITS_API*/ CGradient
{
// Construction
public:
CGradient();
virtual ~CGradient();

// Attributes
public:
// linear gradient attributes
enum eDirection{LTR, RTL, TTB, BTT};
void SetDirection(eDirection fDirection){if(m_fDirection != fDirection){m_fDirection = fDirection;}}
eDirection GetDirection() {
return m_fDirection;}
void SetStretchGradient(float flStretchFactor = 1); // useful for animation
float GetStretchGradient() {return m_flStretchGrad;}
// linear gradient operations
virtual void DrawLinearGradient(CDC *pDC, CRect rcGrad, int nClipStart = 0, int nClipEnd = -1, int nShift = 0);

// attributes
void SetGradientColors(COLORREF clrStart, COLORREF clrEnd) { SetGradientColorsX(2, clrStart, clrEnd);}
void GetGradientColors(COLORREF& clrStart, COLORREF& clrEnd);

void SetGradientColorsX(int nCount, COLORREF clrFirst, COLORREF clrNext, ...);
const CDWordArray& GetGradientColorsX() { return m_ardwGradColors; }
void AddColor(COLORREF clr);
void SetColorsStretch(double flFirst, ...); // in percent, num of arguments should be one less then num of colors

void SetCreatePalette(BOOL fCreate = TRUE) {m_fCreatePalette = fCreate;}
BOOL GetCreatePalette() {
return m_fCreatePalette;}
CPalette
& GetPalette() {CreatePalette(); return m_Pal;}

// operations
virtual void CalcShiftedGradient(CGradArray& arElements, int nShift, int nGradWidth, int nClipStart = 0, int nClipEnd = -1, UINT nMaxColors = (UINT)-1);
virtual void CalcMultiGradient(CGradArray& arElements, int nGradWidth, int nClipStart = 0, int nClipEnd = -1, UINT nMaxColors = (UINT)-1);
virtual void CalcGradient(CGradArray& arElements, COLORREF clrStart, COLORREF clrEnd, int nGradWidth, int nClipStart = 0, int nClipEnd = -1, UINT nMaxColors = (UINT)-1);
protected:
void CreatePalette();
void NormalizeColorsStretch();

// color atributes
CDWordArray m_ardwGradColors;
BOOL m_fCreatePalette;
CPalette m_Pal;
private:
CArray
<double, double&> m_arflGradStretch;
protected:
// linear gradient
eDirection m_fDirection;
CRect ConvertToReal(CRect rcDraw,
int nBandStart, int nBandEnd);
float m_flStretchGrad;
};

#endif // !defined(AFX_GRADIENT_H__2FB4902E_E00C_4892_AA03_60779F349F58__INCLUDED_)

 

Gradient.cpp

 

 

代码
Gradient.cpp

///////////////////////////////////////////////////////////////////////////////
// class CGradient
//

#include
"stdafx.h"
#include
"Gradient.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CGradient::CGradient()
{
m_fCreatePalette
= FALSE;
m_fDirection
= LTR;
m_flStretchGrad
= 1;
}

CGradient::
~CGradient()
{

}

void CGradient::DrawLinearGradient(CDC *pDC, CRect rcGrad, int nClipStart, int nClipEnd, int nShift)
{
BOOL f256Color
= pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE;
if(!f256Color && (pDC->GetDeviceCaps(BITSPIXEL)*pDC->GetDeviceCaps(PLANES) < 8))
{
// for 16 colors no gradient
ASSERT(m_ardwGradColors.GetSize() > 0);
pDC
->FillSolidRect(&ConvertToReal(rcGrad, nClipStart, nClipEnd), m_ardwGradColors[0]);
return;
}

int nGradWidth = 0;
if(m_fDirection == TTB || m_fDirection == BTT)
nGradWidth
= rcGrad.Height(); // vert
else
nGradWidth
= rcGrad.Width(); // horz

if(nClipEnd == -1) nClipEnd = nGradWidth;
ASSERT(nGradWidth
>= nClipEnd);

ASSERT(m_flStretchGrad
>= 1);
nGradWidth
= int(nGradWidth * m_flStretchGrad);

CGradArray arElements;
CalcShiftedGradient(arElements, nShift, nGradWidth, nClipStart, nClipEnd, f256Color
? 236 : -1);
int nSteps = arElements.GetSize();

int nBandStart = nClipStart;
int nBandEnd = nClipStart;

// Start filling
CPalette *pOldPal = NULL;
if (f256Color && m_fCreatePalette && GetPalette().GetSafeHandle())
{
pOldPal
= pDC->SelectPalette(&GetPalette(), FALSE);
pDC
->RealizePalette();
}

for (int i = 0; i < nSteps; i++, nBandStart = nBandEnd)
{
nBandEnd
+= arElements[i].length;

COLORREF nColor
= arElements[i].color;
if(f256Color)
{
if (pOldPal) // in background draw dithered
nColor |= 0x02000000; // (PALETTERGB) without it will be dithering

CBrush br(nColor);
// CDC::FillSolidRect is faster, but it does not handle 8-bit color depth
pDC->FillRect(&ConvertToReal(rcGrad, nBandStart, nBandEnd), &br);
br.DeleteObject();
}
else
pDC
->FillSolidRect(&ConvertToReal(rcGrad, nBandStart, nBandEnd), nColor);
}
if(pOldPal)
pDC
->SelectPalette(pOldPal, TRUE);
}

CRect CGradient::ConvertToReal(CRect rcDraw,
int nBandStart, int nBandEnd)
{
BOOL fReverse
= (m_fDirection == TTB || m_fDirection == RTL);
BOOL fVert
= (m_fDirection == TTB || m_fDirection == BTT);

CRect rc(rcDraw);
if(fVert)
{
if(nBandEnd == -1) nBandEnd = rcDraw.Height();
rc.top
= rcDraw.top +
(fReverse
? nBandStart : (rcDraw.Height() - nBandEnd));
rc.bottom
= rc.top + (nBandEnd - nBandStart);
}
else
{
if(nBandEnd == -1) nBandEnd = rcDraw.Width();
rc.left
= rcDraw.left +
(fReverse
? (rcDraw.Width() - nBandEnd) : nBandStart);
rc.right
= rc.left + (nBandEnd - nBandStart);
}
return rc;
}

void CGradient::CalcShiftedGradient(CGradArray& arElements, int nShift, int nGradWidth,
int nClipStart, int nClipEnd, UINT nMaxColors)
{
// normalize shift
if(nGradWidth == 0)
nShift
= 0;
else
{
while(nShift < 0) nShift += nGradWidth;
nShift
%= nGradWidth;
}

if(nShift == 0 || m_ardwGradColors.GetSize() < 2)
{
CalcMultiGradient(arElements, nGradWidth, nClipStart, nClipEnd, nMaxColors);
return;
}

CGradArray arElementsOrig;
CalcMultiGradient(arElementsOrig, nGradWidth,
0, -1, nMaxColors);
int nCount = arElementsOrig.GetSize();
if(nCount < 2)
{
// no gradient
arElements.Add(CGradElement(m_ardwGradColors[0], nClipEnd - nClipStart));
return;
}

// do shift
CGradArray arElementsShift;
int nLength = 0;
for(int i = nCount-1; i >= 0; i--)
{
CGradElement
& el = arElementsOrig.ElementAt(i);
if(nLength + el.length > nShift)
{
// Separate
arElementsShift.InsertAt(0, CGradElement(el.color, nShift - nLength));
el.length
-= nShift - nLength;
break;
}
else
{
nLength
+= el.length;
arElementsShift.InsertAt(
0, el);
arElementsOrig.RemoveAt(i);
if(nLength == nShift)
break;
}
}
// combine shifted
arElementsShift.Append(arElementsOrig);

// do clip
if(nClipEnd == -1) nClipEnd = nGradWidth;
nCount
= arElementsShift.GetSize();
nLength
= 0;
for(int i = 0; i < nCount; i++)
{
CGradElement
& el = arElementsShift.ElementAt(i);
if(nLength + el.length <= nClipStart)
{
nLength
+= el.length;
continue; // skip before clip start
}
int nStart = max(nLength, nClipStart);
nLength
+= el.length;
int nEnd = min(nLength, nClipEnd);
arElements.Add(CGradElement(el.color, nEnd
- nStart));
if(nLength >= nClipEnd)
break; // skip after clip end
}
}

void CGradient::CalcMultiGradient(CGradArray& arElements, int nGradWidth,
int nClipStart, int nClipEnd, UINT nMaxColors)
{
if(nClipEnd == -1) nClipEnd = nGradWidth;
int nSteps = m_ardwGradColors.GetSize()-1;
if(nSteps < 0)
{
ASSERT(
0); // at least 1 color should be added
return;
}
if(nSteps == 0)
{
arElements.Add(CGradElement(m_ardwGradColors[
0], nClipEnd - nClipStart));
return;
}

double flBandGradStart = 0;

nMaxColors
/= nSteps;
for (int i = 0; i < nSteps; i++)
{
int nBandGradStart = int((double)nGradWidth*flBandGradStart/100);
flBandGradStart
+= m_arflGradStretch[i];
int nBandGradEnd = int((double)nGradWidth*flBandGradStart/100);

if(i == nSteps-1) //last step (because of problems with float)
nBandGradEnd = nGradWidth;

if(nBandGradEnd < nClipStart)
continue; // skip - band before cliping rect

int nBandClipStart = nBandGradStart;
int nBandClipEnd = nBandGradEnd;
if(nBandClipStart < nClipStart)
nBandClipStart
= nClipStart;
if(nBandClipEnd > nClipEnd)
nBandClipEnd
= nClipEnd;

CalcGradient(arElements, m_ardwGradColors[i], m_ardwGradColors[i
+1],
nBandGradEnd
- nBandGradStart,
nBandClipStart
- nBandGradStart,
nBandClipEnd
- nBandGradStart,
nMaxColors);

if(nBandClipEnd == nClipEnd)
break; // stop filling - next band is out of clipping rect
}
}

void CGradient::CalcGradient(CGradArray& arElements, COLORREF clrStart, COLORREF clrEnd,
int nGradWidth, int nClipStart, int nClipEnd,
UINT nMaxColors)
{
if(nClipEnd == -1) nClipEnd = nGradWidth;
// Split colors to RGB chanels, find chanel with maximum difference
// between the start and end colors. This distance will determine
// number of steps of gradient
int r = (GetRValue(clrEnd) - GetRValue(clrStart));
int g = (GetGValue(clrEnd) - GetGValue(clrStart));
int b = (GetBValue(clrEnd) - GetBValue(clrStart));
UINT nSteps
= max(abs(r), max(abs(g), abs(b)));
nSteps
= min(nSteps, nMaxColors);
// if number of pixels in gradient less than number of steps -
// use it as numberof steps
UINT nPixels = nGradWidth;
nSteps
= min(nPixels, nSteps);
if(nSteps == 0) nSteps = 1;

float rStep = (float)r/nSteps;
float gStep = (float)g/nSteps;
float bStep = (float)b/nSteps;

r
= GetRValue(clrStart);
g
= GetGValue(clrStart);
b
= GetBValue(clrStart);

float nWidthPerStep = (float)nGradWidth / nSteps;
CBrush br;
// Start filling
for (UINT i = 0; i < nSteps; i++)
{
int nFillStart = (int)(nWidthPerStep * i);
int nFillEnd = (int)(nWidthPerStep * (i+1));
if(i == nSteps-1) //last step (because of problems with float)
nFillEnd = nGradWidth;

if(nFillEnd < nClipStart)
continue; // skip - band before cliping rect

// clip it
if(nFillStart < nClipStart)
nFillStart
= nClipStart;
if(nFillEnd > nClipEnd)
nFillEnd
= nClipEnd;

COLORREF clrFill
= RGB(r + (int)(i * rStep),
g
+ (int)(i * gStep),
b
+ (int)(i * bStep));
// add band
arElements.Add(CGradElement(clrFill, nFillEnd - nFillStart));

if(nFillEnd >= nClipEnd)
break; // stop filling if we reach current position
}
}

void CGradient::SetGradientColorsX(int nCount, COLORREF clrFirst, COLORREF clrNext, ...)
{
ASSERT(nCount
> 1);
m_ardwGradColors.SetSize(nCount);

m_ardwGradColors.SetAt(
0, clrFirst);
m_ardwGradColors.SetAt(
1, clrNext);

if(nCount > 2)
{
va_list pArgs;
va_start(pArgs, clrNext);
for(int i = 2; i < nCount; i++)
m_ardwGradColors.SetAt(i, va_arg(pArgs, COLORREF));
va_end( pArgs );
}

nCount
--;
m_arflGradStretch.SetSize(nCount);
for(int i = 0; i < nCount; i++)
m_arflGradStretch[i]
= (double)100 / nCount;

// remove all dependent objects
m_Pal.DeleteObject();
}

void CGradient::GetGradientColors(COLORREF& clrStart, COLORREF& clrEnd)
{
if(m_ardwGradColors.GetSize() > 0)
{
clrStart
= m_ardwGradColors[0];
clrEnd
= m_ardwGradColors[m_ardwGradColors.GetSize() > 1 ? 1 : 0];
}
else
clrStart
= clrEnd = CLR_NONE;
}

void CGradient::AddColor(COLORREF clr)
{
m_ardwGradColors.Add(clr);
if(m_ardwGradColors.GetSize() > 1)
{
double flNew = (double)100/m_arflGradStretch.GetSize();
m_arflGradStretch.Add(flNew);
NormalizeColorsStretch();
}
}

void CGradient::CreatePalette()
{
if(!m_fCreatePalette || m_Pal.GetSafeHandle())
return;

int nNumColors = 236;
CGradArray arElements;
CalcMultiGradient(arElements, nNumColors,
0, nNumColors, nNumColors);
ASSERT(nNumColors
>= arElements.GetSize());
nNumColors
= arElements.GetSize();
if(!nNumColors)
return;

LPLOGPALETTE lpPal
= (LPLOGPALETTE)new BYTE[sizeof(LOGPALETTE) +
sizeof(PALETTEENTRY) *
nNumColors];

if (!lpPal)
return;

lpPal
->palVersion = 0x300;
lpPal
->palNumEntries = nNumColors;

for (int i = 0; i < nNumColors; i++)
{
COLORREF nColor
= arElements[i].color;

lpPal
->palPalEntry[i].peRed = GetRValue(nColor);
lpPal
->palPalEntry[i].peGreen = GetGValue(nColor);
lpPal
->palPalEntry[i].peBlue = GetBValue(nColor);
lpPal
->palPalEntry[i].peFlags = 0;
}

m_Pal.CreatePalette(lpPal);

delete [](PBYTE)lpPal;
}

void CGradient::SetStretchGradient(float flStretchFactor)
{
ASSERT(flStretchFactor
>= 1);
if(flStretchFactor < 1)
flStretchFactor
= 1;
m_flStretchGrad
= flStretchFactor;
}

void CGradient::NormalizeColorsStretch()
{
int nCount = m_arflGradStretch.GetSize();
ASSERT(nCount
== m_ardwGradColors.GetSize()-1);
double flFull = 0;
for(int i = 0; i < nCount; i++)
flFull
+= m_arflGradStretch[i];

for(int i = 0; i < nCount; i++)
m_arflGradStretch[i]
= m_arflGradStretch[i] * 100 / flFull;
}

void CGradient::SetColorsStretch(double flFirst, ...)
{
int nCount = m_ardwGradColors.GetSize()-1;
if(nCount < 1)
{
ASSERT(
0); // before you use this function add all necessary colors
return;
}

m_arflGradStretch.SetSize(nCount);
m_arflGradStretch.SetAt(
0, flFirst);
va_list pArgs;
va_start(pArgs, flFirst);
for(int i = 1; i < nCount; i++)
m_arflGradStretch.SetAt(i, va_arg(pArgs,
double));
va_end( pArgs );

NormalizeColorsStretch();
// normalize
}

 

 

 

posted @ 2010-07-22 13:51  宝哥哥  阅读(1130)  评论(0编辑  收藏  举报