?? balloonhelp.cpp
字號(hào):
sizeHdr.cx += nBtnWidth; sizeHdr.cy = max(sizeHdr.cy, ::GetSystemMetrics(SM_CYSIZE)); if (bDraw) pDC->DrawFrameControl(CRect(rectClient.right-nBtnWidth,0,rectClient.right,::GetSystemMetrics(SM_CYSIZE)), DFC_CAPTION, DFCS_CAPTIONCLOSE|DFCS_FLAT); rectClient.right -= nBtnWidth; } // calc title size CString strTitle; GetWindowText(strTitle); if ( !strTitle.IsEmpty() ) { CFont* pOldFont = pDC->SelectObject(m_pTitleFont); // if something is already in the header (icon or close button) leave space if ( sizeHdr.cx > 0 ) sizeHdr.cx += nTIP_MARGIN; CRect rectTitle(0,0,0,0); pDC->DrawText(strTitle, &rectTitle, DT_CALCRECT | DT_NOPREFIX | DT_EXPANDTABS | DT_SINGLELINE); sizeHdr.cx += rectTitle.Width(); sizeHdr.cy = max(sizeHdr.cy, rectTitle.Height()); // draw title if ( bDraw ) { pDC->SetBkMode(TRANSPARENT); pDC->SetTextColor(m_crForeground); pDC->DrawText(strTitle, &rectClient, DT_CENTER | DT_NOPREFIX | DT_EXPANDTABS | DT_SINGLELINE); } // cleanup pDC->SelectObject(pOldFont); } return sizeHdr;
}
// Calculate the dimensions and draw the balloon contents
CSize CBalloonHelp::DrawContent(CDC* pDC, int nTop, bool bDraw)
{
CRect rectContent; GetAnchorScreenBounds(rectContent); rectContent.OffsetRect(-rectContent.left, -rectContent.top); rectContent.top = nTop; // limit to half screen width rectContent.right -= rectContent.Width()/2; // calc size CFont* pOldFont = pDC->SelectObject(m_pContentFont); if ( !m_strContent.IsEmpty() ) pDC->DrawText(m_strContent, &rectContent, DT_CALCRECT | DT_LEFT | DT_NOPREFIX | DT_EXPANDTABS | DT_WORDBREAK); else rectContent.SetRectEmpty(); // don't want to leave half the screen for empty strings ;) // draw if (bDraw) { pDC->SetBkMode(TRANSPARENT); pDC->SetTextColor(m_crForeground); pDC->DrawText(m_strContent, &rectContent, DT_LEFT | DT_NOPREFIX | DT_WORDBREAK | DT_EXPANDTABS); }
// cleanup pDC->SelectObject(pOldFont); return rectContent.Size();
}
// calculates the client size necessary based on title and contentCSize CBalloonHelp::CalcClientSize(){ ASSERT(NULL != m_hWnd); CWindowDC dc(this); CSize sizeHeader = CalcHeaderSize(&dc); CSize sizeContent = CalcContentSize(&dc); return CSize(max(sizeHeader.cx,sizeContent.cx), sizeHeader.cy + nTIP_MARGIN + sizeContent.cy);}// calculates the size for the entire window based on content sizeCSize CBalloonHelp::CalcWindowSize(){ CSize size = CalcClientSize(); size.cx += nTIP_MARGIN*2; size.cy += nTIP_TAIL+nTIP_MARGIN*2; //size.cx = max(size.cx, nTIP_MARGIN*2+nTIP_TAIL*4); return size;}// this routine calculates the size and position of the window relative// to it's anchor point, and moves the window accordingly. The region is also// created and set here.void CBalloonHelp::PositionWindow(){
CSize sizeWnd = CalcWindowSize(); CPoint ptTail[3]; CPoint ptTopLeft(0,0); CPoint ptBottomRight(sizeWnd.cx, sizeWnd.cy); // force recalculation of desktop
m_screenRect.SetRectEmpty();
switch (GetBalloonQuadrant()) { case BQ_TOPLEFT: ptTopLeft.y = nTIP_TAIL; ptTail[0].x = (sizeWnd.cx-nTIP_TAIL)/4 + nTIP_TAIL; ptTail[0].y = nTIP_TAIL+1; ptTail[2].x = (sizeWnd.cx-nTIP_TAIL)/4; ptTail[2].y = ptTail[0].y; ptTail[1].x = ptTail[2].x; ptTail[1].y = 1; break; case BQ_TOPRIGHT: ptTopLeft.y = nTIP_TAIL; ptTail[0].x = (sizeWnd.cx-nTIP_TAIL)/4*3; ptTail[0].y = nTIP_TAIL+1; ptTail[2].x = (sizeWnd.cx-nTIP_TAIL)/4*3 + nTIP_TAIL; ptTail[2].y = ptTail[0].y; ptTail[1].x = ptTail[2].x; ptTail[1].y = 1; break; case BQ_BOTTOMLEFT: ptBottomRight.y = sizeWnd.cy-nTIP_TAIL; ptTail[0].x = (sizeWnd.cx-nTIP_TAIL)/4 + nTIP_TAIL; ptTail[0].y = sizeWnd.cy-nTIP_TAIL-2; ptTail[2].x = (sizeWnd.cx-nTIP_TAIL)/4; ptTail[2].y = ptTail[0].y; ptTail[1].x = ptTail[2].x; ptTail[1].y = sizeWnd.cy-2; break; case BQ_BOTTOMRIGHT: ptBottomRight.y = sizeWnd.cy-nTIP_TAIL; ptTail[0].x = (sizeWnd.cx-nTIP_TAIL)/4*3; ptTail[0].y = sizeWnd.cy-nTIP_TAIL-2; ptTail[2].x = (sizeWnd.cx-nTIP_TAIL)/4*3 + nTIP_TAIL; ptTail[2].y = ptTail[0].y; ptTail[1].x = ptTail[2].x; ptTail[1].y = sizeWnd.cy-2; break; } // adjust for very narrow balloons if ( ptTail[0].x < nTIP_MARGIN ) ptTail[0].x = nTIP_MARGIN; if ( ptTail[0].x > sizeWnd.cx - nTIP_MARGIN ) ptTail[0].x = sizeWnd.cx - nTIP_MARGIN; if ( ptTail[1].x < nTIP_MARGIN ) ptTail[1].x = nTIP_MARGIN; if ( ptTail[1].x > sizeWnd.cx - nTIP_MARGIN ) ptTail[1].x = sizeWnd.cx - nTIP_MARGIN; if ( ptTail[2].x < nTIP_MARGIN ) ptTail[2].x = nTIP_MARGIN; if ( ptTail[2].x > sizeWnd.cx - nTIP_MARGIN ) ptTail[2].x = sizeWnd.cx - nTIP_MARGIN; // get window position CPoint ptAnchor = GetAnchorPoint(); CPoint ptOffs(ptAnchor.x - ptTail[1].x, ptAnchor.y - ptTail[1].y); // adjust position so all is visible CRect rectScreen; GetAnchorScreenBounds(rectScreen); int nAdjustX = 0; int nAdjustY = 0; if ( ptOffs.x < rectScreen.left ) nAdjustX = rectScreen.left-ptOffs.x; else if ( ptOffs.x + sizeWnd.cx >= rectScreen.right ) nAdjustX = rectScreen.right - (ptOffs.x + sizeWnd.cx); if ( ptOffs.y + nTIP_TAIL < rectScreen.top ) nAdjustY = rectScreen.top - (ptOffs.y + nTIP_TAIL); else if ( ptOffs.y + sizeWnd.cy - nTIP_TAIL >= rectScreen.bottom ) nAdjustY = rectScreen.bottom - (ptOffs.y + sizeWnd.cy - nTIP_TAIL); // reposition tail // uncomment two commented lines below to move entire tail // instead of just anchor point //ptTail[0].x -= nAdjustX; ptTail[1].x -= nAdjustX; //ptTail[2].x -= nAdjustX; ptOffs.x += nAdjustX; ptOffs.y += nAdjustY; // place window
MoveWindow(ptOffs.x, ptOffs.y, sizeWnd.cx, sizeWnd.cy, TRUE);
// apply region
CRgn region; CRgn regionRound; CRgn regionComplete; region.CreatePolygonRgn(&ptTail[0], 3, ALTERNATE); regionRound.CreateRoundRectRgn(ptTopLeft.x,ptTopLeft.y,ptBottomRight.x,ptBottomRight.y,nTIP_MARGIN*3,nTIP_MARGIN*3); regionComplete.CreateRectRgn(0,0,1,1); regionComplete.CombineRgn(®ion, ®ionRound, RGN_OR); if ( NULL == m_rgnComplete.m_hObject ) m_rgnComplete.CreateRectRgn(0,0,1,1);
if ( !m_rgnComplete.EqualRgn(®ionComplete) )
{
m_rgnComplete.CopyRgn(®ionComplete); SetWindowRgn((HRGN)regionComplete.Detach(), TRUE);
// There is a bug with layered windows and NC changes in Win2k
// As a workaround, redraw the entire window if the NC area changed.
// Changing the anchor point is the ONLY thing that will change the
// position of the client area relative to the window during normal
// operation.
RedrawWindow(NULL, NULL, RDW_UPDATENOW| RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN);
}
}// Returns the class ATOM for a BalloonHelp control. Registers the class first, if necessary.ATOM CBalloonHelp::GetClassAtom(BOOL bShadowed){ if ( NULL == s_ClassAtom ) { WNDCLASSEX wcx; // Fill in the window class structure with parameters // that describe the main window. wcx.cbSize = sizeof(wcx); // size of structure wcx.style = CS_DBLCLKS|CS_SAVEBITS |CS_DROPSHADOW; // notify of double clicks, save screen under, show dropshadow wcx.lpfnWndProc = AfxWndProc; // points to window procedure wcx.cbClsExtra = 0; // no extra class memory wcx.cbWndExtra = 0; // no extra window memory wcx.hInstance = AfxGetInstanceHandle(); // handle to instance wcx.hIcon = NULL; // no app. icon wcx.hCursor = LoadCursor(NULL,IDC_ARROW); // predefined arrow wcx.hbrBackground = ::GetSysColorBrush(COLOR_WINDOW); // no background brush wcx.lpszMenuName = NULL; // no menu resource wcx.lpszClassName = _T("BalloonHelpClassDS"); // name of window class wcx.hIconSm = NULL; // no small class icon // Register the window class (this may not work if dropshadows are not supported) s_ClassAtomShadowed = RegisterClassEx(&wcx); // Register shadow-less class wcx.style &= ~CS_DROPSHADOW; wcx.lpszClassName = _T("BalloonHelpClass"); s_ClassAtom = RegisterClassEx(&wcx); } if ( bShadowed && NULL != s_ClassAtomShadowed ) return s_ClassAtomShadowed; return s_ClassAtom;}
// Displays the balloon on the screen, performing fade-in if enabled.
void CBalloonHelp::ShowBalloon(void)
{
ShowWindow(SW_SHOWNOACTIVATE);
if ( !(m_unOptions&unDELAY_CLOSE) )
SetTimeout(m_unTimeout); // start close timer}
// Removes the balloon from the screen, performing the fade-out if enabled
void CBalloonHelp::HideBalloon(void)
{
if ( m_unOptions&unDELAY_CLOSE )
{
m_unOptions &= ~(unDELAY_CLOSE|unCLOSE_ON_ANYTHING); // close only via timer or button
SetTimeout(m_unTimeout); // start close timer return; }
ShowWindow( SW_HIDE );
if ( GetCapture() == this )
ReleaseCapture();
DestroyWindow();
}
//
// Keyboard hook
//
void CBalloonHelp::SetKeyboardHook()
{
if ( NULL==m_hKeyboardHook )
{
m_hKeyboardHook = ::SetWindowsHookEx(WH_KEYBOARD,
(HOOKPROC)BHKeybHookThunk<CBalloonHelp>::GetThunk(),
NULL, ::GetCurrentThreadId());
}
}
void CBalloonHelp::RemoveKeyboardHook()
{
if ( NULL!=m_hKeyboardHook )
{
::UnhookWindowsHookEx(m_hKeyboardHook);
m_hKeyboardHook=NULL;
}
}
//
// Mouse hook
//
void CBalloonHelp::SetMouseHook()
{
if ( NULL==m_hMouseHook )
{
m_hMouseHook = ::SetWindowsHookEx(WH_MOUSE,
(HOOKPROC)BHMouseHookThunk<CBalloonHelp>::GetThunk(),
NULL, ::GetCurrentThreadId());
}
}
void CBalloonHelp::RemoveMouseHook()
{
if ( NULL!=m_hMouseHook )
{
::UnhookWindowsHookEx(m_hMouseHook);
m_hMouseHook=NULL;
}
}
//
// Call Window Return hook
//
void CBalloonHelp::SetCallWndRetHook()
{
if ( NULL==m_hCallWndRetHook )
{
m_hCallWndRetHook = ::SetWindowsHookEx(WH_CALLWNDPROCRET,
(HOOKPROC)BHCallWndRetHookThunk<CBalloonHelp>::GetThunk(),
NULL, ::GetCurrentThreadId());
}
}
void CBalloonHelp::RemoveCallWndRetHook()
{
if ( NULL!=m_hCallWndRetHook )
{
::UnhookWindowsHookEx(m_hCallWndRetHook);
m_hCallWndRetHook=NULL;
}
}
/////////////////////////////////////////////////////////////////////////////// CBalloonHelp message handlersBEGIN_MESSAGE_MAP(CBalloonHelp, CWnd) ON_WM_ERASEBKGND() ON_WM_PAINT() ON_WM_NCPAINT() ON_WM_LBUTTONDOWN() ON_WM_LBUTTONUP() ON_WM_NCCALCSIZE()
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -