QTracker.cpp
上传用户:xp9161
上传日期:2009-12-21
资源大小:70k
文件大小:6k
源码类别:

Windows编程

开发平台:

Visual C++

  1. // QTracker.cpp
  2. //
  3. //===============================
  4. // Version 1.1, October 2, 2003
  5. // Version 1.0, August 20, 2003
  6. // (c) Sjaak Priester, Amsterdam
  7. // www.sjaakpriester.nl
  8. #include "StdAfx.h"
  9. #include "QTracker.h"
  10. #include "QBufferDC.h"
  11. #include "afxpriv.h"
  12. QTracker::QTracker(CWnd * pWnd)
  13. : m_pWnd(pWnd)
  14. , m_Point(0)
  15. , m_StartPoint(0)
  16. , m_bTracking(false)
  17. , m_bDirty(false)
  18. {
  19. ASSERT_VALID(pWnd);
  20. }
  21. QTracker::~QTracker(void)
  22. {
  23. }
  24. //  Track mouse, starting at positiom point.
  25. int QTracker::Track(CDC * pDC, UINT nFlags, CPoint point, bool bClipCursor /*= false*/)
  26. {
  27. if (::GetCapture()) return TrackFailed; // Someone else has captured the mouse, cancel
  28. // Give derived class the opportunity to process starting message
  29. int r = OnBeginTrack(nFlags, point);
  30. if (r != TrackContinue) return r; // cancel or success, even before tracking starts...
  31. m_bDirty = false;
  32. // (Added in version 1.1)
  33. m_szDrag.cx = ::GetSystemMetrics(SM_CXDRAG);
  34. m_szDrag.cy = ::GetSystemMetrics(SM_CYDRAG);
  35. m_Point = point;
  36. m_PreviousPoint = m_Point;
  37. m_StartPoint = m_Point;
  38. nFlags &= UpdateMouseFlags; // to be sure
  39. m_bTracking = true;
  40. // Undocumented; don't know what this does, but MFC's CRectTracker calls it too.
  41. ::AfxLockTempMaps();
  42. int oldROP2(R2_COPYPEN);
  43. COLORREF oldBkColor(RGB(0, 0, 0));
  44. if (pDC)
  45. {
  46. // Prepare the dc for NOT-XOR drawing on white.
  47. oldROP2 = pDC->SetROP2(R2_NOTXORPEN);
  48. oldBkColor = pDC->SetBkColor(RGB(255, 255, 255));
  49. // (Added in version 1.1)
  50. pDC->DPtoLP(& m_szDrag);
  51. if (m_szDrag.cx < 0) m_szDrag.cx *= -1;
  52. if (m_szDrag.cy < 0) m_szDrag.cy *= -1;
  53. }
  54. // Let user draw first track object
  55. OnUpdate(pDC, nFlags | UpdateDraw | UpdateFirst);
  56. if (bClipCursor)
  57. {
  58. CRect rcClient;
  59. m_pWnd->GetClientRect(rcClient);
  60. m_pWnd->ClientToScreen(rcClient);
  61. VERIFY(::ClipCursor(rcClient));
  62. }
  63. m_pWnd->SetCapture();
  64. ASSERT(CWnd::GetCapture() == m_pWnd);
  65. ASSERT(r == TrackContinue);
  66. while (r == TrackContinue)
  67. {
  68. MSG msg;
  69. int cnt = 0;
  70. while (! ::PeekMessage(& msg, NULL, 0, 0, PM_REMOVE))
  71. {
  72. // Give the statusbar the opportunity to update itself
  73. // by sending a private MFC message (see <afxpriv.h>).
  74. if (cnt == 0)
  75. ::AfxGetMainWnd()->SendMessageToDescendants(WM_IDLEUPDATECMDUI, TRUE);
  76. cnt++;
  77. }
  78. if (CWnd::GetCapture() != m_pWnd || msg.message == WM_CANCELMODE) r = TrackFailed;
  79. else if (msg.message >= WM_MOUSEFIRST && msg.message <= WM_MOUSELAST)
  80. {
  81. // We use our own class QBufferDC for double buffered drawing.
  82. // We accumulate the removing of the old tracking rectangle
  83. // and the drawing of the new one, and update the screen with
  84. // the result. Thus, screen flicker is avoided.
  85. QBufferDC * pXDC = NULL;
  86. if (pDC)
  87. {
  88. pXDC = new QBufferDC(pDC, NOTSRCINVERT);
  89. // Prepare for NOT-XOR drawing (background color is white by default).
  90. pXDC->SetROP2(R2_NOTXORPEN);
  91. }
  92. // Remove old display feedback
  93. OnUpdate(pXDC, nFlags | UpdateRemove | UpdateEnter);
  94. // These casts ensure that sign is preserved
  95. int x = (int)(short) LOWORD(msg.lParam);
  96. int y = (int)(short) HIWORD(msg.lParam);
  97. // Convert to logical coordinates
  98. CPoint pnt(x, y);
  99. if (pDC) pDC->DPtoLP(& pnt);
  100. // (Changed in version 1.1)
  101. CSize diff = pnt - m_Point;
  102. if (abs(diff.cx) > m_szDrag.cx || abs(diff.cy) > m_szDrag.cy)
  103. {
  104. m_PreviousPoint = m_Point;
  105. m_Point = pnt;
  106. m_bDirty = true;
  107. }
  108. nFlags = (UINT) msg.wParam & UpdateMouseFlags;
  109. // Let user change state
  110. r = OnMouseMessage(msg.message, nFlags, pnt);
  111. // QTracker's state is updated, now draw new track objects.
  112. OnUpdate(pXDC, nFlags | UpdateDraw | UpdateLeave);
  113. // QBufferDC's destructor will update the screen.
  114. if (pDC) delete pXDC;
  115. }
  116. else if (msg.message >= WM_KEYFIRST && msg.message <= WM_KEYLAST)
  117. r = OnKeyMessage(msg.message, (UINT) msg.wParam,
  118. (UINT) LOWORD(msg.lParam), (UINT) HIWORD(msg.lParam));
  119. else r = OnMessage(msg);
  120. }
  121. VERIFY(::ReleaseCapture());
  122. if (bClipCursor) VERIFY(::ClipCursor(NULL));
  123. ::AfxUnlockTempMaps();
  124. m_bTracking = false;
  125. // Let user clean up
  126. OnUpdate(pDC, nFlags | UpdateRemove | UpdateLast);
  127. if (r > 0 && !m_bDirty) r = TrackNoMove;
  128. r = OnEndTrack(r);
  129. if (pDC)
  130. {
  131. // Clean up pDC
  132. pDC->SetROP2(oldROP2);
  133. pDC->SetBkColor(oldBkColor);
  134. }
  135. return r;
  136. }
  137. int QTracker::OnBeginTrack(UINT /*nFlags*/, CPoint /*point*/)
  138. {
  139. return TrackContinue;
  140. }
  141. int QTracker::OnEndTrack(int trackResult)
  142. {
  143. return trackResult;
  144. }
  145. // Update the state of QTracker; should be overridden.
  146. int QTracker::OnMouseMessage(UINT msg, UINT nFlags, CPoint /*point*/)
  147. {
  148. // Default just checks for end of tracking operation.
  149. // return TrackSucceeded if msg == WM_LBUTTONUP,
  150. // return TrackCopy if msg == WM_LBUTTONUP and Ctrl pressed,
  151. // cancel tracking if msg == WM_RBUTTONDOWN,
  152. // otherwise, continue tracking.
  153. if (msg == WM_LBUTTONUP) return (nFlags & MK_CONTROL) ? TrackCopy : TrackSucceeded;
  154. if (msg == WM_RBUTTONDOWN) return TrackCancelled;
  155. return TrackContinue;
  156. }
  157. // Called after pressing or releasing a key during track. May be overridden.
  158. int QTracker::OnKeyMessage(UINT msg, UINT nChar, UINT /*nRepCnt*/, UINT /*nFlags*/)
  159. {
  160. // Default: cancel tracking if escape key pressed.
  161. if (msg == WM_KEYDOWN && nChar == VK_ESCAPE) return TrackCancelled;
  162. return TrackContinue;
  163. }
  164. // Called for any other message during track. May be overridden.
  165. int QTracker::OnMessage(MSG& msg)
  166. {
  167. ::DispatchMessage(& msg);
  168. return TrackContinue;
  169. }
  170. // Called during tracking when screen should be updated. Should be overridden.
  171. void QTracker::OnUpdate(CDC * pDC, UINT /*nMode*/)
  172. {
  173. // Default draws line in debug build, does nothing in release build.
  174. #ifdef _DEBUG
  175. if (pDC)
  176. {
  177. pDC->MoveTo(m_StartPoint);
  178. pDC->LineTo(m_Point);
  179. }
  180. #endif
  181. }