首先:把下面这个头文件加入到你要实现动态显示的工程中:
#if !defined(AFX_TOOLTIPWND_H__2C52D3E4_2F5B_11D2_8FC9_000000000000__INCLUDED_)
#define AFX_TOOLTIPWND_H__2C52D3E4_2F5B_11D2_8FC9_000000000000__INCLUDED_
#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
// ToolTipWnd.h : header file
// Acknowledgements:
// Thanks to Venkatesh who helped me in calculating the intersecting
// point in the ellipse.
/////////////////////////////////////////////////////////////////////////////
// CToolTipWnd window
struct BTOOLINFO {
HWND hwndTool;
CString strToolText;
COLORREF clrToolTextClr;
};
class CToolTipWnd : public CWnd
{
private:
// Construction
LPCTSTR lpWndCls;
public:
CToolTipWnd();
HWND pCurrwnd;
// Attributes
public:
void RelayEvent(LPMSG);
BOOL Create(CWnd*);
bool m_bStuck;
void AddTool(CWnd *pWnd, CString strText, COLORREF clrTextColor=NULL);
void SetWidth(int iWidth) { m_iWidth = iWidth; }
void SetHeight(int iHeight) { m_iHeight = iHeight; }
void SetBkColor(COLORREF clrRef) { m_clrBkColor = clrRef; }
void SetFrameColor(COLORREF clrRef) { m_clrFrameColor = clrRef; }
void SetDefTextColor(COLORREF clrRef) { m_clrTextColor = clrRef; }
void SetFontHeight(int iHeight) { m_iFontHeight = iHeight; }
void SetFontName(CString strFontName) { m_strFontName = strFontName; }
private:
CRgn rgn;
CRgn rgnComb;
CRgn rgnTri;
CRect m_RectText;
CFont m_fontText;
CString m_strText;
bool m_bMouseIn;
COLORREF m_clrTextColor;
COLORREF m_clrBkColor;
COLORREF m_clrFrameColor;
CMapPtrToPtr m_ToolPtr;
int m_iWidth;
int m_iHeight;
int m_iFontHeight;
CString m_strFontName;
HWND m_hParentWnd;
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CToolTipWnd)
protected:
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CToolTipWnd();
// Generated message map functions
protected:
//{{AFX_MSG(CToolTipWnd)
afx_msg void OnPaint();
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_TOOLTIPWND_H__2C52D3E4_2F5B_11D2_8FC9_000000000000__INCLUDED_)
复制到这 之后,停一下。。。。。
///////
第二步,然后把下面这个ToolTipWnd,cpp也加入到该工程中
// ToolTipWnd.cpp : implementation file
//
#include "stdafx.h"
#include "ToolTipWnd.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CToolTipWnd
CToolTipWnd::CToolTipWnd()
{
lpWndCls = AfxRegisterWndClass(0);
//Defaults
m_bMouseIn = false;
m_bStuck = false;
m_iWidth = 100;
m_iHeight = 60;
m_clrBkColor = RGB(249,254,188); //light yellow
m_clrFrameColor = RGB(0,0,255); //blue
m_clrTextColor = RGB(0,0,0); //black
m_iFontHeight = 14;
m_strFontName = "Arial";
pCurrwnd = NULL;
}
CToolTipWnd::~CToolTipWnd()
{
BTOOLINFO *stToolInfo;
CWnd *pWnd;
for(POSITION pos = m_ToolPtr.GetStartPosition(); pos != NULL;)
{
m_ToolPtr.GetNextAssoc(pos, (void *&)pWnd, (void*&) stToolInfo);
delete stToolInfo;
}
m_ToolPtr.RemoveAll();
}
BEGIN_MESSAGE_MAP(CToolTipWnd, CWnd)
//{{AFX_MSG_MAP(CToolTipWnd)
ON_WM_PAINT()
ON_WM_CREATE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CToolTipWnd message handlers
BOOL CToolTipWnd::Create(CWnd* pParentWnd)
{
BOOL bRet = CWnd::CreateEx(NULL, lpWndCls, NULL,
WS_POPUP, 0, 0, m_iWidth, m_iHeight,
pParentWnd->GetSafeHwnd(), NULL, NULL);
m_hParentWnd = pParentWnd->GetSafeHwnd();
if(bRet)
SetOwner(pParentWnd);
return bRet;
}
void CToolTipWnd::OnPaint()
{
CPaintDC dc(this); // device context for painting
CRect rectCl;
GetClientRect(&rectCl);
CRgn rgnComb;
rgnComb.CreateRectRgn(rectCl.left+10,rectCl.top,rectCl.right,rectCl.bottom);
int iRetComb = rgnComb.CombineRgn(&rgnTri, &rgn, RGN_OR);
if(iRetComb==ERROR)
{
AfxMessageBox("ERROR in Combining Region");
return;
}
CBrush pBrush;
pBrush.CreateSolidBrush(m_clrFrameColor);
CBrush pBrush1;
pBrush1.CreateSolidBrush(m_clrBkColor);
dc.FillRgn( &rgnComb, &pBrush1);
dc.FrameRgn(&rgnComb, &pBrush, 2, 1);
dc.SetBkMode(TRANSPARENT);
dc.SetTextColor(m_clrTextColor);
CFont *pFont = dc.SelectObject(&m_fontText);
//dc.Rectangle(&m_RectText);
CSize czTextWidth = dc.GetTextExtent(m_strText);
if( czTextWidth.cx < m_RectText.Width())
dc.DrawText(m_strText, m_RectText, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
else
dc.DrawText(m_strText, m_RectText, DT_CENTER | DT_WORDBREAK);
dc.SelectObject(pFont);
}
int CToolTipWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CWnd::OnCreate(lpCreateStruct) == -1)
return -1;
CRect rectCl;
GetClientRect(&rectCl);
int x=0, y=0;
CRect rectTemp;
rectTemp = rectCl;
rectTemp.left = rectTemp.left + 10;
x = (int)( (float)((float)rectTemp.Width() / 2.0) / 1.41421);
y = (int)( (float)((float)rectTemp.Height() / 2.0) / 1.41421);
m_RectText.top = ( (rectTemp.Height() / 2) - y);
m_RectText.left = ( (rectTemp.Width() / 2) - x) + 10;
m_RectText.right = ( (rectTemp.Width() / 2) + x) + 10;
m_RectText.bottom = ( (rectTemp.Height() / 2) + y);
rgn.m_hObject = NULL;
rgnTri.m_hObject = NULL;
rgnComb.m_hObject = NULL;
BOOL bRegRet = rgn.CreateEllipticRgn(rectCl.left+10,rectCl.top,rectCl.right,rectCl.bottom);
CPoint ptTri[3];
ptTri[0].x = rectCl.left;
ptTri[0].y = (rectCl.bottom / 2) - 10;
ptTri[1].x = rectCl.left + 15;
ptTri[1].y = (rectCl.bottom / 2) - 5;
ptTri[2].x = rectCl.left + 15;
ptTri[2].y = (rectCl.bottom / 2) + 5;
ptTri[3].x = rectCl.left;
ptTri[3].y = (rectCl.bottom / 2) - 10;
BOOL bRegTriRet = rgnTri.CreatePolygonRgn(ptTri, 3, ALTERNATE);
rgnComb.CreateRectRgn(rectCl.left+10,rectCl.top,rectCl.right,rectCl.bottom);
int iRetComb = rgnComb.CombineRgn(&rgnTri, &rgn, RGN_OR);
if(iRetComb == ERROR)
{
AfxMessageBox("ERROR in Combining Region");
return -1;
}
int bRgnWnd = SetWindowRgn(rgnComb.operator HRGN( ), TRUE);
m_fontText.CreateFont(m_iFontHeight, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,m_strFontName);
return 0;
}
void CToolTipWnd::RelayEvent(LPMSG lpMsg)
{
switch(lpMsg->message)
{
case WM_KEYDOWN:
if(IsWindowVisible())
{
ShowWindow(SW_HIDE);
}
break;
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
if(IsWindowVisible())
{
ShowWindow(SW_HIDE);
}
break;
case WM_MOUSEMOVE:
{
CWnd *pFocusWnd = AfxGetApp()->m_pMainWnd->GetFocus();
if(pFocusWnd==NULL)
break;
CWnd* pWnd = CWnd::FromHandle(lpMsg->hwnd);
HWND hWndTemp = ::GetParent(lpMsg->hwnd);
CPoint pt;
pt.x = lpMsg->pt.x;
pt.y = lpMsg->pt.y;
BTOOLINFO *stToolInfo;
CWnd *pBToolWnd;
for(POSITION pos = m_ToolPtr.GetStartPosition(); pos != NULL;)
{
m_ToolPtr.GetNextAssoc(pos, (void *&)pBToolWnd, (void*&) stToolInfo);
if(!m_bMouseIn)
{
if(lpMsg->hwnd == stToolInfo->hwndTool)
{
if(m_bStuck && IsWindowVisible())
{
SetWindowPos(&wndTop,pt.x,pt.y,m_iWidth,m_iHeight,SWP_NOACTIVATE);
ShowWindow(SW_SHOWNOACTIVATE);
}
m_bMouseIn = true;
m_clrTextColor = stToolInfo->clrToolTextClr;
m_strText = stToolInfo->strToolText;
SetWindowPos(&wndTop,pt.x,pt.y,m_iWidth,m_iHeight,SWP_NOACTIVATE);
ShowWindow(SW_SHOWNOACTIVATE);
pCurrwnd = stToolInfo->hwndTool;
break;
}
}
else
{
CRect rect;
::GetWindowRect(pCurrwnd, &rect);
if(m_bStuck && IsWindowVisible())
{
SetWindowPos(&wndTop,pt.x,pt.y,m_iWidth,m_iHeight,SWP_NOACTIVATE);
ShowWindow(SW_SHOWNOACTIVATE);
}
CWnd* pWnd = CWnd::FromHandle(lpMsg->hwnd);
CWnd *WndPt = pWnd->WindowFromPoint(lpMsg->pt);
if(WndPt->GetSafeHwnd() != pCurrwnd)
{
m_bMouseIn = false;
ShowWindow(SW_HIDE);
}
break;
}
}
}
break; //WM_MOUSEMOVE
}
}
void CToolTipWnd::AddTool(CWnd *pWnd, CString strText, COLORREF clrTextColor)
{
BTOOLINFO *stToolInfo;
if(!m_ToolPtr.Lookup( pWnd, ( void*& ) stToolInfo))
{
stToolInfo = new BTOOLINFO;
stToolInfo->hwndTool = pWnd->GetSafeHwnd();
stToolInfo->strToolText = strText;
if(clrTextColor==NULL)
stToolInfo->clrToolTextClr = m_clrTextColor;
else
stToolInfo->clrToolTextClr = clrTextColor;
m_ToolPtr.SetAt(pWnd, stToolInfo);
}
}
第三步,把第一步的头文件包含在要用到气球式提示的cpp中,
第四步,
在对话框类中添加成员变量: m_BalloonToolTip,类型为:CToolTipWnd
然后在对话框中的 OnInitDialog()函数中 添加如下代码:
m_BalloonToolTip.Create(this);
m_BalloonToolTip..AddTool(GetDlgItem(控件ID号),"提示信息",RGB(60,50,100));
接下来要重新实现虚函数PreTranslateMessage(Msg* pMsg)
在对话框类的头文件中加入这一个函数定义:
BOOL PreTranslateMessage(Msg* pMsg);
然后,在重新实现该函数,也就是在cpp文件中加入下面这段代码
BooL CTestDlg::PreTranslateMessage(Msg* pMsg)
{
if(m_BalloonToolTip)
m_BalloonToolTip.RelayEvent(pMsg);
}
最后,编译,如果你人品好的话,恭喜你了,大功告成.