CRectTracker(橡皮筋)类

来源:互联网 发布:大型网络竞技游戏 编辑:程序博客网 时间:2024/04/28 21:56

1、CKaRectTracker.h

#pragma once#define CRIT_RECTTRACKER    5void AFXAPI AfxLockGlobals(int nLockType);void AFXAPI AfxUnlockGlobals(int nLockType);void AFXAPI AfxDeleteObject(HGDIOBJ* pObject);/*============================================================================*/// CKaRectTracker - simple rectangular tracking rectangle w/resize handlesclass CKaRectTracker{public:// ConstructorsCKaRectTracker();CKaRectTracker(LPCRECT lpSrcRect, UINT nStyle);// Style Flagsenum StyleFlags{solidLine = 1, dottedLine = 2, hatchedBorder = 4,resizeInside = 8, resizeOutside = 16, hatchInside = 32,};// Hit-Test codesenum TrackerHit{hitNothing = -1,hitTopLeft = 0, hitTopRight = 1, hitBottomRight = 2, hitBottomLeft = 3,hitTop = 4, hitRight = 5, hitBottom = 6, hitLeft = 7, hitMiddle = 8};// AttributesUINT m_nStyle;      // current stateCRect m_rect;       // current position (always in pixels)CSize m_sizeMin;    // minimum X and Y size during track operationint m_nHandleSize;  // size of resize handles (default from WIN.INI)// Operationsvoid Draw(CDC* pDC) const;void GetTrueRect(LPRECT lpTrueRect) const;BOOL SetCursor(CWnd* pWnd, UINT nHitTest) const;BOOL Track(CWnd* pWnd, CPoint point, BOOL bAllowInvert = FALSE,CWnd* pWndClipTo = NULL);BOOL TrackRubberBand(CWnd* pWnd, CPoint point, BOOL bAllowInvert = TRUE);int HitTest(CPoint point) const;int NormalizeHit(int nHandle) const;// Overridablesvirtual void DrawTrackerRect(LPCRECT lpRect, CWnd* pWndClipTo,CDC* pDC, CWnd* pWnd);virtual void AdjustRect(int nHandle, LPRECT lpRect);virtual void OnChangedRect(const CRect& rectOld);virtual UINT GetHandleMask() const;// Implementationpublic:virtual ~CKaRectTracker();protected:BOOL m_bAllowInvert;    // flag passed to Track or TrackRubberBandCRect m_rectLast;CSize m_sizeLast;BOOL m_bErase;          // TRUE if DrawTrackerRect is called for erasingBOOL m_bFinalErase;     // TRUE if DragTrackerRect called for final erase// implementation helpersint HitTestHandles(CPoint point) const;void GetHandleRect(int nHandle, CRect* pHandleRect) const;void GetModifyPointers(int nHandle, int**ppx, int**ppy, int* px, int*py);virtual int GetHandleSize(LPCRECT lpRect = NULL) const;BOOL TrackHandle(int nHandle, CWnd* pWnd, CPoint point, CWnd* pWndClipTo);void Construct();};


2、CKaRectTracker.cpp

// This is a part of the Microsoft Foundation Classes C++ library.// Copyright (C) Microsoft Corporation// All rights reserved.//// This source code is only intended as a supplement to the// Microsoft Foundation Classes Reference and related// electronic documentation provided with the library.// See these sources for detailed information regarding the// Microsoft Foundation Classes product.#include "stdafx.h"#include "KaRectTracker.h"#define new DEBUG_NEW/////////////////////////////////////////////////////////////////////////////// CKaRectTracker global state// various GDI objects we need to drawAFX_STATIC_DATA HCURSOR _afxCursors[10] = { 0, };AFX_STATIC_DATA HBRUSH _afxHatchBrush = 0;AFX_STATIC_DATA HPEN _afxBlackDottedPen = 0;AFX_STATIC_DATA int _afxHandleSize = 0;void AFX_CDECL AfxTrackerTerm(){AfxDeleteObject((HGDIOBJ*)&_afxHatchBrush);AfxDeleteObject((HGDIOBJ*)&_afxBlackDottedPen);}char _afxTrackerTerm = 0;// the struct below is used to determine the qualities of a particular handlestruct AFX_HANDLEINFO{size_t nOffsetX;    // offset within RECT for X coordinatesize_t nOffsetY;    // offset within RECT for Y coordinateint nCenterX;       // adjust X by Width()/2 * this numberint nCenterY;       // adjust Y by Height()/2 * this numberint nHandleX;       // adjust X by handle size * this numberint nHandleY;       // adjust Y by handle size * this numberint nInvertX;       // handle converts to this when X invertedint nInvertY;       // handle converts to this when Y inverted};// this array describes all 8 handles (clock-wise)AFX_STATIC_DATA const AFX_HANDLEINFO _afxHandleInfo[] ={// corner handles (top-left, top-right, bottom-right, bottom-left{ offsetof(RECT, left), offsetof(RECT, top),        0, 0,  0,  0, 1, 3 },{ offsetof(RECT, right), offsetof(RECT, top),       0, 0, -1,  0, 0, 2 },{ offsetof(RECT, right), offsetof(RECT, bottom),    0, 0, -1, -1, 3, 1 },{ offsetof(RECT, left), offsetof(RECT, bottom),     0, 0,  0, -1, 2, 0 },// side handles (top, right, bottom, left){ offsetof(RECT, left), offsetof(RECT, top),        1, 0,  0,  0, 4, 6 },{ offsetof(RECT, right), offsetof(RECT, top),       0, 1, -1,  0, 7, 5 },{ offsetof(RECT, left), offsetof(RECT, bottom),     1, 0,  0, -1, 6, 4 },{ offsetof(RECT, left), offsetof(RECT, top),        0, 1,  0,  0, 5, 7 }};// the struct below gives us information on the layout of a RECT struct and//  the relationship between its membersstruct AFX_RECTINFO{size_t nOffsetAcross;   // offset of opposite point (ie. left->right)int nSignAcross;        // sign relative to that point (ie. add/subtract)};// this array is indexed by the offset of the RECT member / sizeof(int)AFX_STATIC_DATA const AFX_RECTINFO _afxRectInfo[] ={{ offsetof(RECT, right), +1 },{ offsetof(RECT, bottom), +1 },{ offsetof(RECT, left), -1 },{ offsetof(RECT, top), -1 },};/////////////////////////////////////////////////////////////////////////////// CKaRectTracker intitializationCKaRectTracker::CKaRectTracker(LPCRECT lpSrcRect, UINT nStyle){ASSERT(AfxIsValidAddress(lpSrcRect, sizeof(RECT), FALSE));Construct();m_rect.CopyRect(lpSrcRect);m_nStyle = nStyle;}CKaRectTracker::CKaRectTracker(){Construct();}void CKaRectTracker::Construct(){// do one-time initialization if necessaryAfxLockGlobals(CRIT_RECTTRACKER);static BOOL bInitialized;if (!bInitialized){// sanity checks for assumptions we make in the codeASSERT(sizeof(((RECT*)NULL)->left) == sizeof(int));ASSERT(offsetof(RECT, top) > offsetof(RECT, left));ASSERT(offsetof(RECT, right) > offsetof(RECT, top));ASSERT(offsetof(RECT, bottom) > offsetof(RECT, right));if (_afxHatchBrush == NULL){// create the hatch pattern + bitmapWORD hatchPattern[8];WORD wPattern = 0x1111;for (int i = 0; i < 4; i++){hatchPattern[i] = wPattern;hatchPattern[i+4] = wPattern;wPattern <<= 1;}HBITMAP hatchBitmap = CreateBitmap(8, 8, 1, 1, hatchPattern);if (hatchBitmap == NULL){AfxUnlockGlobals(CRIT_RECTTRACKER);AfxThrowResourceException();}// create black hatched brush_afxHatchBrush = CreatePatternBrush(hatchBitmap);DeleteObject(hatchBitmap);if (_afxHatchBrush == NULL){AfxUnlockGlobals(CRIT_RECTTRACKER);AfxThrowResourceException();}}if (_afxBlackDottedPen == NULL){// create black dotted pen_afxBlackDottedPen = CreatePen(PS_DOT, 0, RGB(0, 0, 0));if (_afxBlackDottedPen == NULL){AfxUnlockGlobals(CRIT_RECTTRACKER);AfxThrowResourceException();}}// Note: all track cursors must live in same moduleHINSTANCE hInst = AfxFindResourceHandle(ATL_MAKEINTRESOURCE(AFX_IDC_TRACK4WAY), ATL_RT_GROUP_CURSOR);// initialize the cursor array_afxCursors[0] = ::LoadCursorW(hInst, ATL_MAKEINTRESOURCEW(AFX_IDC_TRACKNWSE));_afxCursors[1] = ::LoadCursorW(hInst, ATL_MAKEINTRESOURCEW(AFX_IDC_TRACKNESW));_afxCursors[2] = _afxCursors[0];_afxCursors[3] = _afxCursors[1];_afxCursors[4] = ::LoadCursorW(hInst, ATL_MAKEINTRESOURCEW(AFX_IDC_TRACKNS));_afxCursors[5] = ::LoadCursorW(hInst, ATL_MAKEINTRESOURCEW(AFX_IDC_TRACKWE));_afxCursors[6] = _afxCursors[4];_afxCursors[7] = _afxCursors[5];_afxCursors[8] = ::LoadCursorW(hInst, ATL_MAKEINTRESOURCEW(AFX_IDC_TRACK4WAY));_afxCursors[9] = ::LoadCursorW(hInst, ATL_MAKEINTRESOURCEW(AFX_IDC_MOVE4WAY));// get default handle size from Windows profile settingstatic const TCHAR szWindows[] = _T("windows");static const TCHAR szInplaceBorderWidth[] =_T("oleinplaceborderwidth");_afxHandleSize = GetProfileInt(szWindows, szInplaceBorderWidth, 4);bInitialized = TRUE;}if (!_afxTrackerTerm)_afxTrackerTerm = (char)!atexit(&AfxTrackerTerm);AfxUnlockGlobals(CRIT_RECTTRACKER);m_nStyle = 0;m_nHandleSize = _afxHandleSize;m_sizeMin.cy = m_sizeMin.cx = m_nHandleSize*2;m_rectLast.SetRectEmpty();m_sizeLast.cx = m_sizeLast.cy = 0;m_bErase = FALSE;m_bFinalErase =  FALSE;}CKaRectTracker::~CKaRectTracker(){}/////////////////////////////////////////////////////////////////////////////// CKaRectTracker operationsvoid CKaRectTracker::Draw(CDC* pDC) const{// set initial DC stateVERIFY(pDC->SaveDC() != 0);pDC->SetMapMode(MM_TEXT);pDC->SetViewportOrg(0, 0);pDC->SetWindowOrg(0, 0);// get normalized rectangleCRect rect = m_rect;rect.NormalizeRect();CPen* pOldPen = NULL;CBrush* pOldBrush = NULL;CGdiObject* pTemp;int nOldROP;// draw linesif ((m_nStyle & (dottedLine|solidLine)) != 0){if (m_nStyle & dottedLine)pOldPen = pDC->SelectObject(CPen::FromHandle(_afxBlackDottedPen));elsepOldPen = (CPen*)pDC->SelectStockObject(BLACK_PEN);pOldBrush = (CBrush*)pDC->SelectStockObject(NULL_BRUSH);nOldROP = pDC->SetROP2(R2_COPYPEN);rect.InflateRect(+1, +1);   // borders are one pixel outsidepDC->Rectangle(rect.left, rect.top, rect.right, rect.bottom);pDC->SetROP2(nOldROP);}// if hatchBrush is going to be used, need to unrealize itif ((m_nStyle & (hatchInside|hatchedBorder)) != 0)UnrealizeObject(_afxHatchBrush);// hatch insideif ((m_nStyle & hatchInside) != 0){pTemp = pDC->SelectStockObject(NULL_PEN);if (pOldPen == NULL)pOldPen = (CPen*)pTemp;pTemp = pDC->SelectObject(CBrush::FromHandle(_afxHatchBrush));if (pOldBrush == NULL)pOldBrush = (CBrush*)pTemp;pDC->SetBkMode(TRANSPARENT);nOldROP = pDC->SetROP2(R2_MASKNOTPEN);pDC->Rectangle(rect.left+1, rect.top+1, rect.right, rect.bottom);pDC->SetROP2(nOldROP);}// draw hatched borderif ((m_nStyle & hatchedBorder) != 0){pTemp = pDC->SelectObject(CBrush::FromHandle(_afxHatchBrush));if (pOldBrush == NULL)pOldBrush = (CBrush*)pTemp;pDC->SetBkMode(OPAQUE);CRect rectTrue;GetTrueRect(&rectTrue);pDC->PatBlt(rectTrue.left, rectTrue.top, rectTrue.Width(),rect.top-rectTrue.top, 0x000F0001 /* Pn */);pDC->PatBlt(rectTrue.left, rect.bottom,rectTrue.Width(), rectTrue.bottom-rect.bottom, 0x000F0001 /* Pn */);pDC->PatBlt(rectTrue.left, rect.top, rect.left-rectTrue.left,rect.Height(), 0x000F0001 /* Pn */);pDC->PatBlt(rect.right, rect.top, rectTrue.right-rect.right,rect.Height(), 0x000F0001 /* Pn */);}// draw resize handlesif ((m_nStyle & (resizeInside|resizeOutside)) != 0){UINT mask = GetHandleMask();for (int i = 0; i < 8; ++i){if (mask & (1<<i)){GetHandleRect((TrackerHit)i, &rect);pDC->FillSolidRect(rect, RGB(0, 0, 0));}}}// cleanup pDC stateif (pOldPen != NULL)pDC->SelectObject(pOldPen);if (pOldBrush != NULL)pDC->SelectObject(pOldBrush);VERIFY(pDC->RestoreDC(-1));}BOOL CKaRectTracker::SetCursor(CWnd* pWnd, UINT nHitTest) const{// trackers should only be in client areaif (nHitTest != HTCLIENT)return FALSE;// convert cursor position to client co-ordinatesCPoint point;GetCursorPos(&point);pWnd->ScreenToClient(&point);// do hittest and normalize hitint nHandle = HitTestHandles(point);if (nHandle < 0)return FALSE;// need to normalize the hittest such that we get proper cursorsnHandle = NormalizeHit(nHandle);// handle special case of hitting area between handles//  (logically the same -- handled as a move -- but different cursor)if (nHandle == hitMiddle && !m_rect.PtInRect(point)){// only for trackers with hatchedBorder (ie. in-place resizing)if (m_nStyle & hatchedBorder)nHandle = (TrackerHit)9;}ENSURE(nHandle < _countof(_afxCursors));::SetCursor(_afxCursors[nHandle]);return TRUE;}int CKaRectTracker::HitTest(CPoint point) const{TrackerHit hitResult = hitNothing;CRect rectTrue;GetTrueRect(&rectTrue);ASSERT(rectTrue.left <= rectTrue.right);ASSERT(rectTrue.top <= rectTrue.bottom);if (rectTrue.PtInRect(point)){if ((m_nStyle & (resizeInside|resizeOutside)) != 0)hitResult = (TrackerHit)HitTestHandles(point);elsehitResult = hitMiddle;}return hitResult;}int CKaRectTracker::NormalizeHit(int nHandle) const{ENSURE(nHandle <= 8 && nHandle >= -1);if (nHandle == hitMiddle || nHandle == hitNothing)return nHandle;ENSURE(0 <= nHandle && nHandle < _countof(_afxHandleInfo));const AFX_HANDLEINFO* pHandleInfo = &_afxHandleInfo[nHandle];if (m_rect.Width() < 0){nHandle = (TrackerHit)pHandleInfo->nInvertX;ENSURE(0 <= nHandle && nHandle < _countof(_afxHandleInfo));pHandleInfo = &_afxHandleInfo[nHandle];}if (m_rect.Height() < 0)nHandle = (TrackerHit)pHandleInfo->nInvertY;return nHandle;}BOOL CKaRectTracker::Track(CWnd* pWnd, CPoint point, BOOL bAllowInvert,   CWnd* pWndClipTo){// perform hit testing on the handlesint nHandle = HitTestHandles(point);if (nHandle < 0){// didn't hit a handle, so just return FALSEreturn FALSE;}// otherwise, call helper function to do the trackingm_bAllowInvert = bAllowInvert;return TrackHandle(nHandle, pWnd, point, pWndClipTo);}BOOL CKaRectTracker::TrackRubberBand(CWnd* pWnd, CPoint point, BOOL bAllowInvert){// simply call helper function to track from bottom right handlem_bAllowInvert = bAllowInvert;m_rect.SetRect(point.x, point.y, point.x, point.y);return TrackHandle(hitBottomRight, pWnd, point, NULL);}void CKaRectTracker::DrawTrackerRect(LPCRECT lpRect, CWnd* pWndClipTo, CDC* pDC, CWnd* pWnd){// first, normalize the rectangle for drawingCRect rect = *lpRect;rect.NormalizeRect();// convert to client coordinatesif (pWndClipTo != NULL){pWnd->ClientToScreen(&rect);pWndClipTo->ScreenToClient(&rect);}CSize size(0, 0);if (!m_bFinalErase){// otherwise, size depends on the styleif (m_nStyle & hatchedBorder){size.cx = size.cy = max(1, GetHandleSize(rect)-1);rect.InflateRect(size);}else{size.cx = AFX_CX_BORDER;size.cy = AFX_CY_BORDER;}}// and draw itif (m_bFinalErase || !m_bErase)pDC->DrawDragRect(rect, size, m_rectLast, m_sizeLast);// remember last rectanglesm_rectLast = rect;m_sizeLast = size;}void CKaRectTracker::AdjustRect(int nHandle, LPRECT){if (nHandle == hitMiddle)return;// convert the handle into locations within m_rectint *px, *py;GetModifyPointers(nHandle, &px, &py, NULL, NULL);// enforce minimum widthint nNewWidth = m_rect.Width();int nAbsWidth = m_bAllowInvert ? abs(nNewWidth) : nNewWidth;if (px != NULL && nAbsWidth < m_sizeMin.cx){nNewWidth = nAbsWidth != 0 ? nNewWidth / nAbsWidth : 1;ptrdiff_t iRectInfo = (int*)px - (int*)&m_rect;ENSURE(0 <= iRectInfo && iRectInfo < _countof(_afxRectInfo));const AFX_RECTINFO* pRectInfo = &_afxRectInfo[iRectInfo];*px = *(int*)((BYTE*)&m_rect + pRectInfo->nOffsetAcross) +nNewWidth * m_sizeMin.cx * -pRectInfo->nSignAcross;}// enforce minimum heightint nNewHeight = m_rect.Height();int nAbsHeight = m_bAllowInvert ? abs(nNewHeight) : nNewHeight;if (py != NULL && nAbsHeight < m_sizeMin.cy){nNewHeight = nAbsHeight != 0 ? nNewHeight / nAbsHeight : 1;ptrdiff_t iRectInfo = (int*)py - (int*)&m_rect;ENSURE(0 <= iRectInfo && iRectInfo < _countof(_afxRectInfo));const AFX_RECTINFO* pRectInfo = &_afxRectInfo[iRectInfo];*py = *(int*)((BYTE*)&m_rect + pRectInfo->nOffsetAcross) +nNewHeight * m_sizeMin.cy * -pRectInfo->nSignAcross;}}void CKaRectTracker::GetTrueRect(LPRECT lpTrueRect) const{ASSERT(AfxIsValidAddress(lpTrueRect, sizeof(RECT)));CRect rect = m_rect;rect.NormalizeRect();int nInflateBy = 0;if ((m_nStyle & (resizeOutside|hatchedBorder)) != 0)nInflateBy += GetHandleSize() - 1;if ((m_nStyle & (solidLine|dottedLine)) != 0)++nInflateBy;rect.InflateRect(nInflateBy, nInflateBy);*lpTrueRect = rect;}void CKaRectTracker::OnChangedRect(const CRect& /*rectOld*/){// no default implementation, useful for derived classes}/////////////////////////////////////////////////////////////////////////////// CKaRectTracker implementation helpersvoid CKaRectTracker::GetHandleRect(int nHandle, CRect* pHandleRect) const{ASSERT(nHandle < 8);// get normalized rectangle of the trackerCRect rectT = m_rect;rectT.NormalizeRect();if ((m_nStyle & (solidLine|dottedLine)) != 0)rectT.InflateRect(+1, +1);// since the rectangle itself was normalized, we also have to invert the//  resize handles.nHandle = NormalizeHit(nHandle);// handle case of resize handles outside the trackerint size = GetHandleSize();if (m_nStyle & resizeOutside)rectT.InflateRect(size-1, size-1);// calculate position of the resize handleint nWidth = rectT.Width();int nHeight = rectT.Height();CRect rect;const AFX_HANDLEINFO* pHandleInfo = &_afxHandleInfo[nHandle];rect.left = *(int*)((BYTE*)&rectT + pHandleInfo->nOffsetX);rect.top = *(int*)((BYTE*)&rectT + pHandleInfo->nOffsetY);rect.left += size * pHandleInfo->nHandleX;rect.top += size * pHandleInfo->nHandleY;rect.left += pHandleInfo->nCenterX * (nWidth - size) / 2;rect.top += pHandleInfo->nCenterY * (nHeight - size) / 2;rect.right = rect.left + size;rect.bottom = rect.top + size;*pHandleRect = rect;}int CKaRectTracker::GetHandleSize(LPCRECT lpRect) const{if (lpRect == NULL)lpRect = &m_rect;int size = m_nHandleSize;if (!(m_nStyle & resizeOutside)){// make sure size is small enough for the size of the rectint sizeMax = min(abs(lpRect->right - lpRect->left),abs(lpRect->bottom - lpRect->top));if (size * 2 > sizeMax)size = sizeMax / 2;}return size;}int CKaRectTracker::HitTestHandles(CPoint point) const{CRect rect;UINT mask = GetHandleMask();// see if hit anywhere inside the trackerGetTrueRect(&rect);if (!rect.PtInRect(point))return hitNothing;  // totally missed// see if we hit a handlefor (int i = 0; i < 8; ++i){if (mask & (1<<i)){GetHandleRect((TrackerHit)i, &rect);if (rect.PtInRect(point))return (TrackerHit)i;}}// last of all, check for non-hit outside of object, between resize handlesif ((m_nStyle & hatchedBorder) == 0){CRect rect = m_rect;rect.NormalizeRect();if ((m_nStyle & dottedLine|solidLine) != 0)rect.InflateRect(+1, +1);if (!rect.PtInRect(point))return hitNothing;  // must have been between resize handles}return hitMiddle;   // no handle hit, but hit object (or object border)}BOOL CKaRectTracker::TrackHandle(int nHandle, CWnd* pWnd, CPoint point, CWnd* pWndClipTo){ASSERT(nHandle >= 0);ASSERT(nHandle <= 8);   // handle 8 is inside the rect// don't handle if capture already setif (::GetCapture() != NULL)return FALSE;AfxLockTempMaps();  // protect maps while loopingASSERT(!m_bFinalErase);// save original width & height in pixelsint nWidth = m_rect.Width();int nHeight = m_rect.Height();// set capture to the window which received this messagepWnd->SetCapture();ASSERT(pWnd == CWnd::GetCapture());pWnd->UpdateWindow();if (pWndClipTo != NULL)pWndClipTo->UpdateWindow();CRect rectSave = m_rect;// find out what x/y coords we are supposed to modifyint *px, *py;int xDiff, yDiff;GetModifyPointers(nHandle, &px, &py, &xDiff, &yDiff);xDiff = point.x - xDiff;yDiff = point.y - yDiff;// get DC for drawingCDC* pDrawDC;if (pWndClipTo != NULL){// clip to arbitrary window by using adjusted Window DCpDrawDC = pWndClipTo->GetDCEx(NULL, DCX_CACHE);}else{// otherwise, just use normal DCpDrawDC = pWnd->GetDC();}ENSURE_VALID(pDrawDC);CRect rectOld;BOOL bMoved = FALSE;// get messages until capture lost or cancelled/acceptedfor (;;){MSG msg;VERIFY(::GetMessage(&msg, NULL, 0, 0));if (CWnd::GetCapture() != pWnd)break;switch (msg.message){// handle movement/accept messagescase WM_LBUTTONUP:case WM_MOUSEMOVE:rectOld = m_rect;// handle resize cases (and part of move)if (px != NULL)*px = GET_X_LPARAM(msg.lParam) - xDiff;if (py != NULL)*py = GET_Y_LPARAM(msg.lParam) - yDiff;// handle move caseif (nHandle == hitMiddle){m_rect.right = m_rect.left + nWidth;m_rect.bottom = m_rect.top + nHeight;}// allow caller to adjust the rectangle if necessaryAdjustRect(nHandle, &m_rect);// only redraw and callback if the rect actually changed!m_bFinalErase = (msg.message == WM_LBUTTONUP);if (!rectOld.EqualRect(&m_rect) || m_bFinalErase){if (bMoved){m_bErase = TRUE;DrawTrackerRect(&rectOld, pWndClipTo, pDrawDC, pWnd);}OnChangedRect(rectOld);if (msg.message != WM_LBUTTONUP)bMoved = TRUE;}if (m_bFinalErase)goto ExitLoop;if (!rectOld.EqualRect(&m_rect)){m_bErase = FALSE;DrawTrackerRect(&m_rect, pWndClipTo, pDrawDC, pWnd);}break;// handle cancel messagescase WM_KEYDOWN:if (msg.wParam != VK_ESCAPE)break;case WM_RBUTTONDOWN:if (bMoved){m_bErase = m_bFinalErase = TRUE;DrawTrackerRect(&m_rect, pWndClipTo, pDrawDC, pWnd);}m_rect = rectSave;goto ExitLoop;// just dispatch rest of the messagesdefault:DispatchMessage(&msg);break;}}ExitLoop:if (pWndClipTo != NULL)pWndClipTo->ReleaseDC(pDrawDC);elsepWnd->ReleaseDC(pDrawDC);ReleaseCapture();AfxUnlockTempMaps(FALSE);// restore rect in case bMoved is still FALSEif (!bMoved)m_rect = rectSave;m_bFinalErase = FALSE;m_bErase = FALSE;// return TRUE only if rect has changedreturn !rectSave.EqualRect(&m_rect);}void CKaRectTracker::GetModifyPointers(int nHandle, int** ppx, int** ppy, int* px, int* py){ENSURE(nHandle >= 0);ENSURE(nHandle <= 8);if (nHandle == hitMiddle)nHandle = hitTopLeft;   // same as hitting top-left*ppx = NULL;*ppy = NULL;// fill in the part of the rect that this handle modifies//  (Note: handles that map to themselves along a given axis when that//   axis is inverted don't modify the value on that axis)const AFX_HANDLEINFO* pHandleInfo = &_afxHandleInfo[nHandle];if (pHandleInfo->nInvertX != nHandle){*ppx = (int*)((BYTE*)&m_rect + pHandleInfo->nOffsetX);if (px != NULL)*px = **ppx;}else{// middle handle on X axisif (px != NULL)*px = m_rect.left + abs(m_rect.Width()) / 2;}if (pHandleInfo->nInvertY != nHandle){*ppy = (int*)((BYTE*)&m_rect + pHandleInfo->nOffsetY);if (py != NULL)*py = **ppy;}else{// middle handle on Y axisif (py != NULL)*py = m_rect.top + abs(m_rect.Height()) / 2;}}UINT CKaRectTracker::GetHandleMask() const{UINT mask = 0x0F;   // always have 4 corner handlesint size = m_nHandleSize*3;if (abs(m_rect.Width()) - size > 4)mask |= 0x50;if (abs(m_rect.Height()) - size > 4)mask |= 0xA0;return mask;}/////////////////////////////////////////////////////////////////////////////


3、调用示例:

(1)包含头文件,声明一个成员变量:CKaRectTracker m_kaRectTracker;

(2)在OnInitDialog中初始化橡皮筋类:

m_kaRectTracker.m_nStyle=CRectTracker::resizeInside|CRectTracker::dottedLine;//设置RectTracker样式
m_kaRectTracker.m_nHandleSize = 5; //控制柄的像素大小
m_kaRectTracker.m_rect.SetRect(0,0,0,0); //初始化m_rect的值

(3)响应LButtonDown事件:

CRect cwrect;GetWindowRect(&cwrect); //获取窗体中控件的区域ScreenToClient(&cwrect); //转换为相对区域的CRect  if(point.x>cwrect.left && point.y>cwrect.top    //确保按下的坐标在控件区域内   && point.x{if(m_kaRectTracker.HitTest(point)<0)     //如果未击中矩形选择框,重新画选择框{             m_kaRectTracker.TrackRubberBand(this,point,TRUE);m_kaRectTracker.m_rect.NormalizeRect();   //正规化矩形(关于正规化矩形下面有介绍)}else           //如果击中矩形选择框{  m_kaRectTracker.Track(this,point,TRUE);m_kaRectTracker.m_rect.NormalizeRect();   //正规化矩形//SendMessage(WM_LBUTTONUP,NULL,NULL);}Invalidate();   //刷新窗口区域,使得CrectTracker对象重绘到窗口上}

(4)OnPaint函数中:

m_kaRectTracker.Draw(&dc);//将这个四边形选区画出来


4、效果如下:



5、说明:该类是由MFC类CRectTracker中提取出来的,以便根据需求做出相应的修改。





0 0
原创粉丝点击