效果图:
代码:
InputCheckTip.h
#pragma once
#include "Resource.h"
#include "SSWnd.h"
// CWndInputCheck 窗口
#define TIMER_HIDETIP 1001
class CWndInputCheck : public CSSWnd
{
DECLARE_DYNAMIC(CWndInputCheck)
public:
CWndInputCheck(CWnd* pParent = NULL); // 标准构造函数
virtual ~CWndInputCheck();
protected:
DYNAMIC_FONT m_lf; //静态文字字体
CString m_strText;
DYNAMIC_RGB m_clrBkg;
DYNAMIC_RGB m_clrStcTips; //白
CRect m_rcMain;
int m_nalainside;
int m_nalainoffset;
DYNAMIC_IMAGE m_pimgWarning;
protected:
DECLARE_MESSAGE_MAP()
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnPaint();
afx_msg void OnSize(UINT nType, int cx, int cy);
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
afx_msg void OnTimer(UINT_PTR nIDEvent);
public:
void SetFont(DYNAMIC_FONT lf);
void SetText(const CString &str);
void SetMainRect(int alainside, int alainoffst, const CRect &mainrc);
const CRect &GetMainRect();
};
enum TIPTYPE{
/*
0 - 自己指定的任意字符串。
1 - 请确保输入在"x1" - "x2"范围内。
2 - 请确保输入内容形如以下形式:
"xxxxxxxxxxx"
*/
TIP_ERR_CUSTOM,
TIP_ERR_RANGE,
TIP_ERR_LIKE,
};
//CWndInputCheckTip 窗口
class SSCOMMON_API CInputCheckTip
{
public:
//公共的tip
static CInputCheckTip *GetTipInstance();
//关联窗口的tip
static CInputCheckTip *GetTipInstance(HWND hWnd);
//注销
static void UnInitInstance();//GdiplusShutdown之前调用
// 外部接口
// 关联窗口的tip需要额外调用:
static void AddInputCheckTip(CWnd *pWnd);//在OnCreate中调用
//公共,关联tip共有接口
/*
nTipType取值 参考 enum TIPTYPE
*/
void PopTip(HWND hWnd, CPoint &point, TIPTYPE nTipType, const CString &sText1,const CString &sText2 = CString(_T("")),const CString &sText3 = CString(_T("")));
void PopTip(HWND hWnd, CRect &rect, TIPTYPE nTipType, const CString &sText1,const CString &sText2 = CString(_T("")),const CString &sText3 = CString(_T("")));
void HideTip();
protected:
CInputCheckTip(CWnd* pParent = NULL); // 标准构造函数
virtual ~CInputCheckTip();
const CString &strWndInputCheck(int i);
static LRESULT MyMsgProc(HWND hwnd,UINT message, WPARAM wParam, LPARAM lParam);
static LRESULT MyMsgProcHwnd(HWND hwnd,UINT message, WPARAM wParam, LPARAM lParam);
protected:
CWndInputCheck* m_pWndInputCheck;
HWND m_hWnd;
WNDPROC m_OldMsgProc;
bool m_bMoving;
CRect m_rcOld;
static CInputCheckTip* m_instance;
static std::map<HWND,CInputCheckTip*> m_tipmap;
};
InputCheckTip.cpp
#include "stdafx.h"//-支持关联窗口的多实例
#include "InputCheckTip.h"
#include "SSCommonApp.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif // _DEBUG
IMPLEMENT_DYNAMIC(CWndInputCheck, CSSWnd)
CWndInputCheck::CWndInputCheck( CWnd* pParent /*= NULL*/ )
{
m_clrBkg = SkinMgr::GetColor(clrCheckTipBack);//0x00BAE9FF;
m_clrStcTips = SkinMgr::GetColor(clrCheckTipText);
m_pimgWarning = SkinMgr::AddImage(PNG_INPUT_CHECK_WARNING);
}
CWndInputCheck::~CWndInputCheck()
{
SkinMgr::DelImage(m_pimgWarning);
}
BEGIN_MESSAGE_MAP(CWndInputCheck, CSSWnd)
ON_WM_CREATE()
ON_WM_SIZE()
ON_WM_ERASEBKGND()
ON_WM_TIMER()
ON_WM_PAINT()
END_MESSAGE_MAP()
int CWndInputCheck::OnCreate( LPCREATESTRUCT lpCreateStruct )
{
if (CSSWnd::OnCreate(lpCreateStruct) == -1)
return -1;
m_lf = SkinMgr::GetFont(fnt3);
return 0;
}
void CWndInputCheck::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: 在此处添加消息处理程序代码
Graphics graph(dc.GetSafeHdc());
CRect rcClient;
GetClientRect(&rcClient);
Color clrBkg;
clrBkg.SetFromCOLORREF(TORGB(m_clrBkg));
SolidBrush brush(clrBkg);
graph.FillRectangle(&brush,rcClient.left,rcClient.top,rcClient.Width(),rcClient.Height());
Rect rc;
rc.X = m_rcMain.left + 8;
rc.Y = (m_rcMain.top + m_rcMain.bottom - TOPIMAGE(m_pimgWarning)->GetHeight())/2;
rc.Width = TOPIMAGE(m_pimgWarning)->GetWidth();
rc.Height = TOPIMAGE(m_pimgWarning)->GetHeight();
graph.DrawImage(TOPIMAGE(m_pimgWarning),rc);
int nTextleft = rc.X+TOPIMAGE(m_pimgWarning)->GetWidth() + 10;
int nTextwidth = m_rcMain.Width()-nTextleft-4;
StringFormat sf;
sf.SetAlignment(StringAlignmentNear);
sf.SetLineAlignment(StringAlignmentCenter);
sf.SetTrimming(StringTrimmingNone);
sf.SetFormatFlags(StringFormatFlagsNoWrap);
Color txtColor;
txtColor.SetFromCOLORREF(TORGB(m_clrStcTips));
SolidBrush txtBrush(txtColor);
Gdiplus::Font font(dc.GetSafeHdc(), m_lf);
RectF rf = RectF(nTextleft,m_rcMain.top+8,nTextwidth,m_rcMain.Height()-16);
graph.DrawString(m_strText,m_strText.GetLength(),&font,rf,&sf,&txtBrush);
// RectF rf = RectF(nTextleft,m_rcMain.top+4,nTextwidth,m_lf.lfHeight);
// graph.DrawString(StringTable.strWndInputCheck(0),StringTable.strWndInputCheck(0).GetLength(),&font,rf,&sf,&txtBrush);
//
// Color lineColor;
// lineColor.SetFromCOLORREF(0x808080);
// Pen pen(lineColor);
// graph.DrawLine(&pen,Point(nTextleft,m_rcMain.top + 4 + m_lf.lfHeight + 3),Point(m_rcMain.Width()-4,m_rcMain.top + 4 + m_lf.lfHeight + 3));
// // graph.DrawLine(&pen,Point(nTextleft-5,m_rcMain.top + 4),Point(nTextleft-5,m_rcMain.bottom - 4));
//
// rf = RectF(nTextleft,m_rcMain.top + 4 + m_lf.lfHeight + 7,nTextwidth,m_rcMain.bottom-4-(m_rcMain.top + 4 + m_lf.lfHeight + 7));
// graph.DrawString(m_strText,m_strText.GetLength(),&font,rf,&sf,&txtBrush);
// 不为绘图消息调用 CSSWnd::OnPaint()
}
BOOL CWndInputCheck::OnEraseBkgnd(CDC* pDC)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
return TRUE;
// return CSSWnd::OnEraseBkgnd(pDC);
}
void CWndInputCheck::OnSize( UINT nType, int cx, int cy )
{
if(cx <=0 || cy <= 0)
{
return;
}
CPoint ptVertex[3];
switch (m_nalainside)
{
case 0://left
{
ptVertex[0].x = 0; ptVertex[0].y = m_nalainoffset;
ptVertex[1].x = m_rcMain.left; ptVertex[1].y = m_nalainoffset - 10;
ptVertex[2].x = m_rcMain.left; ptVertex[2].y = m_nalainoffset + 10;
}
break;
case 1://top
{
ptVertex[0].x = m_nalainoffset; ptVertex[0].y = 0;
ptVertex[1].x = m_nalainoffset - 10; ptVertex[1].y = m_rcMain.top;
ptVertex[2].x = m_nalainoffset + 10; ptVertex[2].y = m_rcMain.top;
}
break;
case 2://right
{
ptVertex[0].x = cx; ptVertex[0].y = m_nalainoffset;
ptVertex[1].x = m_rcMain.right; ptVertex[1].y = m_nalainoffset - 10;
ptVertex[2].x = m_rcMain.right; ptVertex[2].y = m_nalainoffset + 10;
}
break;
case 3://bottom
{
ptVertex[0].x = m_nalainoffset; ptVertex[0].y = cy;
ptVertex[1].x = m_nalainoffset - 10; ptVertex[1].y = m_rcMain.bottom;
ptVertex[2].x = m_nalainoffset + 10; ptVertex[2].y = m_rcMain.bottom;
}
break;
default:
break;
}
HRGN rgn1 = CreateRectRgn(m_rcMain.left,m_rcMain.top,m_rcMain.right,m_rcMain.bottom);
HRGN rgn2 = CreatePolygonRgn(ptVertex,3,ALTERNATE);
CombineRgn(rgn1,rgn1,rgn2,RGN_OR);
SetWindowRgn((HRGN)rgn1,TRUE);
DeleteObject(rgn1);
DeleteObject(rgn2);
Invalidate(TRUE);
}
void CWndInputCheck::OnTimer(UINT_PTR nIDEvent)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
if (nIDEvent == TIMER_HIDETIP)
{
KillTimer(nIDEvent);
ShowWindow(SW_HIDE);
}
CSSWnd::OnTimer(nIDEvent);
}
void CWndInputCheck::SetFont(DYNAMIC_FONT lf)
{
m_lf = lf;
}
void CWndInputCheck::SetText(const CString &str)
{
m_strText = str;
}
void CWndInputCheck::SetMainRect(int alainside, int alainoffst, const CRect &mainrc)
{
m_nalainside = alainside;
m_nalainoffset = alainoffst;
m_rcMain = mainrc;
CRect rc;
GetWindowRect(&rc);
OnSize(SIZE_RESTORED,rc.Width(),rc.Height());
}
//CWndInputCheckTip 窗口
CInputCheckTip* CInputCheckTip::m_instance = NULL;
std::map<HWND,CInputCheckTip*> CInputCheckTip::m_tipmap;
CInputCheckTip::CInputCheckTip(CWnd* pParent /*= NULL*/)
: m_pWndInputCheck(NULL)
, m_hWnd(NULL)
, m_OldMsgProc(NULL)
, m_bMoving(false)
{
if (NULL == m_instance || m_tipmap.empty())
{
//注册窗口
WNDCLASS wc;
memset(&wc, 0, sizeof(WNDCLASS));
wc.style = 0;
wc.lpfnWndProc = ::DefWindowProc;
wc.hInstance = AfxGetInstanceHandle();
wc.hIcon = NULL;
wc.hCursor = NULL;
wc.hbrBackground = HBRUSH(GetStockObject(NULL_BRUSH));
wc.lpszMenuName = NULL;
wc.lpszClassName = _T("CWndInputCheck");
if (!AfxRegisterClass(&wc))
{
TRACE(_T("CWndInputCheck Class registration Failer\n"));
}
}
m_pWndInputCheck = new CWndInputCheck(pParent);
m_pWndInputCheck->CreateEx(WS_EX_TOOLWINDOW,_T("CWndInputCheck"),NULL,WS_POPUP/*|WS_VISIBLE*/,CRect(0,0,0,0),pParent,0);
}
CInputCheckTip::~CInputCheckTip()
{
m_pWndInputCheck->DestroyWindow();
delete m_pWndInputCheck;
int instcount = m_tipmap.size();
if (NULL != m_instance)
{
++instcount;
}
if (instcount <= 1)
{
if(!UnregisterClass(_T("CWndInputCheck"),AfxGetInstanceHandle()))
{
TRACE(_T("CWndInputCheck Class unregistration Failer\n"));
}
}
}
CInputCheckTip * CInputCheckTip::GetTipInstance()
{
if(NULL == m_instance)
{
m_instance = new CInputCheckTip;
}
return m_instance;
}
CInputCheckTip * CInputCheckTip::GetTipInstance(HWND hWnd)
{
CInputCheckTip *pTip = NULL;
std::map<HWND, CInputCheckTip *>::iterator it = m_tipmap.find(hWnd);
if(it != m_tipmap.end())
{
pTip = it->second;
}
return pTip;
}
void CInputCheckTip::AddInputCheckTip(CWnd *pWnd)
{
if (!pWnd || !(pWnd->GetSafeHwnd()))
{
return;
}
HWND hWnd = pWnd->GetSafeHwnd();
std::map<HWND, CInputCheckTip *>::iterator it = m_tipmap.find(hWnd);
if(it == m_tipmap.end())
{
CInputCheckTip *pTip = new CInputCheckTip(pWnd);
bool binsert = m_tipmap.insert(std::make_pair(hWnd,pTip)).second;
if(!binsert)
{
delete pTip;
}
WNDPROC OldMsgProc = (WNDPROC)SetWindowLong(hWnd, GWL_WNDPROC, (LONG)MyMsgProcHwnd);
m_tipmap[hWnd]->m_OldMsgProc = OldMsgProc;
// m_tipmap.insert(std::make_pair(hWnd,new CInputCheckTip(CWnd::FromHandle(hWnd)))).first->second->m_OldMsgProc = (WNDPROC)SetWindowLong(hWnd, GWL_WNDPROC, (LONG)MyMsgProcHwnd);
}
}
void CInputCheckTip::UnInitInstance()
{
if (NULL != m_instance)
{
delete m_instance;
m_instance = NULL;
}
std::map<HWND, CInputCheckTip *>::iterator it = m_tipmap.begin();
for (; it != m_tipmap.end(); ++it)
{
delete it ->second;
}
m_tipmap.clear();
}
LRESULT CInputCheckTip::MyMsgProc(HWND hwnd,UINT message, WPARAM wParam, LPARAM lParam)
{
static BOOL bfirst = TRUE;
static CRect rcP;
if(message == WM_MOVING)
{
if (bfirst)
{
GetWindowRect(hwnd,&rcP);
}
bfirst = FALSE;
}
if(message == WM_MOVE)
{
//bfirst = TRUE;
//int x = LOWORD(lParam);
//int y = HIWORD(lParam);
//CRect rc;
//GetTipInstance()->m_pWndInputCheck->GetWindowRect(&rc);
//rc += CPoint(LOWORD(lParam)-rcP.left,HIWORD(lParam)-rcP.top);
//GetTipInstance()->m_pWndInputCheck->MoveWindow(&rc,FALSE);
bfirst = TRUE;
CRect rc, rcEndP;
GetWindowRect(hwnd, &rcEndP);
GetTipInstance()->m_pWndInputCheck->GetWindowRect(&rc);
rc += CPoint(rcEndP.left-rcP.left,rcEndP.top-rcP.top);
GetTipInstance()->m_pWndInputCheck->MoveWindow(&rc,FALSE);
}
if (message == WM_SHOWWINDOW)
{
if(GetTipInstance(hwnd)->m_pWndInputCheck->IsWindowVisible())
{
if (!(TRUE == BOOL(wParam)))
{
GetTipInstance(hwnd)->m_pWndInputCheck->ShowWindow(SW_HIDE);
}
}
}
if (message == WM_CLOSE || message == WM_DESTROY)
{
GetTipInstance()->m_pWndInputCheck->ShowWindow(SW_HIDE);
}
return CallWindowProc(GetTipInstance()->m_OldMsgProc,hwnd,message,wParam,lParam);
}
LRESULT CInputCheckTip::MyMsgProcHwnd(HWND hwnd,UINT message, WPARAM wParam, LPARAM lParam)
{
if(message == WM_MOVING)
{
if (!GetTipInstance(hwnd)->m_bMoving)
{
GetTipInstance(hwnd)->m_bMoving = true;
GetWindowRect(hwnd,&(GetTipInstance(hwnd)->m_rcOld));
}
}
if(message == WM_MOVE)
{
//GetTipInstance(hwnd)->m_bMoving = false;
//int x = LOWORD(lParam);
//int y = HIWORD(lParam);
//CRect rc;
//GetTipInstance(hwnd)->m_pWndInputCheck->GetWindowRect(&rc);
//rc += CPoint(LOWORD(lParam)-GetTipInstance(hwnd)->m_rcOld.left,HIWORD(lParam)-GetTipInstance(hwnd)->m_rcOld.top);
//GetTipInstance(hwnd)->m_pWndInputCheck->MoveWindow(&rc,FALSE);
GetTipInstance(hwnd)->m_bMoving = false;
CRect rc, rcEndP;
GetWindowRect(hwnd, &rcEndP);
GetTipInstance(hwnd)->m_pWndInputCheck->GetWindowRect(&rc);
rc += CPoint(rcEndP.left-GetTipInstance(hwnd)->m_rcOld.left,rcEndP.top-GetTipInstance(hwnd)->m_rcOld.top);
GetTipInstance(hwnd)->m_pWndInputCheck->MoveWindow(&rc,FALSE);
}
if (message == WM_SHOWWINDOW)
{
if(GetTipInstance(hwnd)->m_pWndInputCheck->IsWindowVisible())
{
if (!(TRUE == BOOL(wParam)))
{
GetTipInstance(hwnd)->m_pWndInputCheck->ShowWindow(SW_HIDE);
}
}
}
if (message == WM_CLOSE || message == WM_NCDESTROY)
{
GetTipInstance(hwnd)->m_pWndInputCheck->ShowWindow(SW_HIDE);
if(message == WM_NCDESTROY)
{
std::map<HWND, CInputCheckTip *>::iterator it = m_tipmap.find(hwnd);
if (it != m_tipmap.end())
{
WNDPROC wndproc = it->second->m_OldMsgProc;
delete it ->second;
m_tipmap.erase(it);
return CallWindowProc(wndproc,hwnd,message,wParam,lParam);
}
}
}
return CallWindowProc(GetTipInstance(hwnd)->m_OldMsgProc,hwnd,message,wParam,lParam);
}
const CString &CInputCheckTip::strWndInputCheck(int i)
{
switch(i)
{
case 1:{_return(_T("请确保输入数值大于\"{1}\"。"),_T(""));break;}
case 2:{_return(_T("请确保输入数值小于\"{2}\"。"),_T(""));break;}
case 3:{_return(_T("请确保输入在\"{1}\" - \"{2}\"范围内。"),_T(""));break;}
case 4:{_return(_T("请确保输入内容形如以下形式:\n\"{1}\""),_T(""));break;}
default:break;
}
return m_strNULL;
}
void CInputCheckTip::PopTip(HWND hWnd, CPoint &point, int nTipType, const CString &sText1,const CString &sText2,const CString &sText3)
{
if (!hWnd || !IsWindow(hWnd))
{
return ;
}
if (m_tipmap.find(hWnd) == m_tipmap.end())
{
if (m_hWnd && IsWindow(m_hWnd))
{
SetWindowLong (m_hWnd, GWL_WNDPROC, (LONG)m_OldMsgProc);
}
m_hWnd = hWnd;
m_OldMsgProc=(WNDPROC)SetWindowLong (m_hWnd, GWL_WNDPROC, (LONG)MyMsgProc);
}
CString sztmp = nTipType==TIP_ERR_RANGE ? (sText2 == _T("") ? strWndInputCheck(1)
:
sText1 == _T("") ? strWndInputCheck(2)
: strWndInputCheck(3))
:
nTipType==TIP_ERR_LIKE ? strWndInputCheck(4)
: _T("{1}");
sztmp.Replace(_T("{1}"),sText1);
sztmp.Replace(_T("{2}"),sText2);
sztmp.Replace(_T("{3}"),sText3);
DYNAMIC_FONT lf = SkinMgr::GetFont(fnt3);
CDC* pDC = m_pWndInputCheck->GetDC();
Graphics graph(pDC->GetSafeHdc());
Gdiplus::Font font(pDC->GetSafeHdc(), lf);
RectF rf;
CRect rcTip;
graph.MeasureString(sztmp,sztmp.GetLength(),&font,PointF(0,0),&rf);
m_pWndInputCheck->ReleaseDC(pDC);
rcTip.left = (LONG)(0);
rcTip.top = (LONG)(0);
rcTip.right = (LONG)(rf.Width+16+16+10);
rcTip.bottom = (LONG)(rf.Height+16);
int x = GetSystemMetrics(SM_XVIRTUALSCREEN );
int y = GetSystemMetrics(SM_YVIRTUALSCREEN );
int cx = GetSystemMetrics(SM_CXVIRTUALSCREEN);
int cy = GetSystemMetrics(SM_CYVIRTUALSCREEN);
CRect DsktopRc(x,y,cx,cy);
int alainside = -1;
if (!(point.y - rcTip.Height() - 15 < DsktopRc.top))
{
alainside = 3;//bottom
}
if (alainside==-1 && !(point.y + rcTip.Height() + 15 > DsktopRc.bottom))
{
alainside = 1;
}
if (alainside==-1)
{
alainside = 3;
}
int alainoffset=20, offset = point.x-20-DsktopRc.left;
if (offset<0)
{
if (offset>-10)
{
alainoffset += offset;
}
else
{
alainside = 0;//left;
}
}
if (alainside != 0 && !(offset < 0))
{
offset = point.x-20+rcTip.Width()-DsktopRc.right;
if (offset>0)
{
if (offset<rcTip.Width()-30)
{
alainoffset += offset;
}
else
{
alainside = 2;//right;
}
}
}
CRect rcTipReal = rcTip;
switch(alainside)
{
case 0:
{
rcTip.left -= 15;
rcTip += CPoint(point.x+15,point.y-alainoffset);
rcTipReal += CPoint(15,0);
}
break;
case 1:
{
rcTip.top -= 15;
rcTip += CPoint(point.x-alainoffset,point.y+15);
rcTipReal += CPoint(0,15);
}
break;
case 2:
{
rcTip.right += 15;
rcTip += CPoint(point.x-rcTip.Width(),point.y-alainoffset);
}
break;
case 3:
{
rcTip.bottom += 15;
rcTip += CPoint(point.x-alainoffset,point.y-rcTip.Height());
}
break;
default:
break;
}
m_pWndInputCheck->SetMainRect(alainside,alainoffset,rcTipReal);
m_pWndInputCheck->SetFont(lf);
m_pWndInputCheck->SetText(sztmp);
m_pWndInputCheck->MoveWindow(&rcTip);
m_pWndInputCheck->ShowWindow(SW_SHOWNOACTIVATE);
m_pWndInputCheck->SetWindowPos(&CWnd::wndTopMost,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_NOREDRAW);
m_pWndInputCheck->SetWindowPos(&CWnd::wndNoTopMost,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_NOREDRAW);
m_pWndInputCheck->KillTimer(TIMER_HIDETIP);
m_pWndInputCheck->SetTimer(TIMER_HIDETIP,3000,NULL);
}
void CInputCheckTip::PopTip(HWND hWnd, CRect &rect , int nTipType, const CString &sText1,const CString &sText2,const CString &sText3)
{
if (!hWnd)
{
return ;
}
if (m_tipmap.find(hWnd) == m_tipmap.end())
{
if (m_hWnd && IsWindow(m_hWnd))
{
SetWindowLong (m_hWnd, GWL_WNDPROC, (LONG)m_OldMsgProc);
}
m_hWnd = hWnd;
m_OldMsgProc=(WNDPROC)SetWindowLong (m_hWnd, GWL_WNDPROC, (LONG)MyMsgProc);
}
CString sztmp = nTipType==TIP_ERR_RANGE ? (sText2 == _T("") ? strWndInputCheck(1)
:
sText1 == _T("") ? strWndInputCheck(2)
: strWndInputCheck(3))
:
nTipType==TIP_ERR_LIKE ? strWndInputCheck(4)
: _T("{1}");
sztmp.Replace(_T("{1}"),sText1);
sztmp.Replace(_T("{2}"),sText2);
sztmp.Replace(_T("{3}"),sText3);
DYNAMIC_FONT lf = SkinMgr::GetFont(fnt3);
CDC* pDC = m_pWndInputCheck->GetDC();
Graphics graph(pDC->GetSafeHdc());
Gdiplus::Font font(pDC->GetSafeHdc(), lf);
RectF rf;
CRect rcTip;
graph.MeasureString(sztmp,sztmp.GetLength(),&font,PointF(0,0),&rf);
m_pWndInputCheck->ReleaseDC(pDC);
rcTip.left = (LONG)(0);
rcTip.top = (LONG)(0);
rcTip.right = (LONG)(rf.Width+16+16+10);
rcTip.bottom = (LONG)(rf.Height+16);
//{
int x = GetSystemMetrics(SM_XVIRTUALSCREEN );
int y = GetSystemMetrics(SM_YVIRTUALSCREEN );
int cx = GetSystemMetrics(SM_CXVIRTUALSCREEN);
int cy = GetSystemMetrics(SM_CYVIRTUALSCREEN);
CRect DsktopRc(x,y,cx,cy);
CRect pointrc;//并不是一个实际的Rect
pointrc.left = max(rect.left,min(rect.left+5, cx));
pointrc.right = min(rect.right,max(rect.right-5,x));
pointrc.top = max(rect.top,min(rect.top+5, cy));
pointrc.bottom= min(rect.bottom,max(rect.bottom-5,y));
int alainside = -1;
if (!(pointrc.top - rcTip.Height() - 15 < DsktopRc.top))
{
alainside = 3;//bottom
}
if (alainside==-1 && !(pointrc.bottom + rcTip.Height() + 15 > DsktopRc.bottom))
{
alainside = 1;//top
}
if (alainside==-1)
{
alainside = 3;
}
int alainoffset=20, offset = pointrc.left-20-DsktopRc.left, rectoffset = 0;
if (offset<0)
{
if (offset>-pointrc.Width())
{
rectoffset -= offset;
}
else if (offset>-pointrc.Width()-10)
{
rectoffset = pointrc.Width();
alainoffset += (offset+pointrc.Width());
}
else
{
alainside = 0;//left;
}
}
if (alainside != 0 && !(offset<0))
{
offset = pointrc.left-20+rcTip.Width()-DsktopRc.right;
if (offset>0)
{
if (offset<rcTip.Width()-30)
{
alainoffset += offset;
}
else
{
alainside = 2;//right;
}
}
}
CRect rcTipReal = rcTip;
//}
switch(alainside)
{
case 0:
{
rcTip.left -= 15;
rcTip += CPoint(pointrc.right+15,pointrc.top-alainoffset);
rcTipReal += CPoint(15,0);
}
break;
case 1:
{
rcTip.top -= 15;
rcTip += CPoint(pointrc.left+rectoffset-alainoffset,pointrc.bottom+15);
rcTipReal += CPoint(0,15);
}
break;
case 2:
{
rcTip.right += 15;
rcTip += CPoint(pointrc.left-rcTip.Width(),pointrc.top-alainoffset);
}
break;
case 3:
{
rcTip.bottom += 15;
rcTip += CPoint(pointrc.left+rectoffset-alainoffset,pointrc.top-rcTip.Height());
}
break;
default:
break;
}
m_pWndInputCheck->SetMainRect(alainside,alainoffset,rcTipReal);
m_pWndInputCheck->SetFont(lf);
m_pWndInputCheck->SetText(sztmp);
m_pWndInputCheck->MoveWindow(&rcTip);
m_pWndInputCheck->ShowWindow(SW_SHOWNOACTIVATE);
m_pWndInputCheck->SetWindowPos(&CWnd::wndTopMost,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_NOREDRAW);
m_pWndInputCheck->SetWindowPos(&CWnd::wndNoTopMost,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_NOREDRAW);
m_pWndInputCheck->KillTimer(TIMER_HIDETIP);
m_pWndInputCheck->SetTimer(TIMER_HIDETIP,3000,NULL);
}
void CInputCheckTip::HideTip()
{
if (m_pWndInputCheck->IsWindowVisible())
{
m_pWndInputCheck->ShowWindow(SW_HIDE);
}
}
使用:
//1.在输入控件等需要检查的控件附着的弹出式窗口的OnCreate中调用:
CInputCheckTip::AddInputCheckTip(this);
//2.在控件焦点切换或者其他时机,检查输入,如果不满足限制条件使用一下代码弹出提示:
CInputCheckTip::GetTipInstance(GetSafeHwnd())->PopTip(GetSafeHwnd(), rc/*控件的桌面坐标矩形*/,TIP_ERR_CUSTOM,_T("输入有误!"));