Multiple CRectTracker Class | CodeGuru

Multiple CRectTracker Class

. Environment: VC6 SP2, NT4 SP3, Win95/98 The class I present performs the classic dragging and resizing of multiple objects, like vectoriel editors or CAD programs. It does the same operations that the CRectTracker, with an array of rectangles instead of a single rectangle. Those rectangles could be implemented with a CArray, but the […]

Written By
CodeGuru Staff
CodeGuru Staff
Feb 5, 2000
2 minute read
CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More

.

Environment: VC6 SP2, NT4 SP3, Win95/98

The class I present performs the classic dragging and resizing of multiple
objects, like vectoriel editors or CAD programs.
It does the same operations that the CRectTracker, with an array of rectangles
instead of a single rectangle.

Those rectangles could be implemented with a CArray<CRect*, CRect*>,
but the code in the project’s view would be complex and not portable. So
my solution is the CMRTObject (for CMultiRectTrackerObject), a base class
for the edited objects, with just a rectangle information and two functions
Get/Set. In a normal project, those objects are often based on CObject,
but with multiple inheritance, this add-in is easy to be implemented. Another
good news is that the CMultiRectTracker class gets the possibility to directly
change the position/size of selected objects, so the CView code for the
manipulation is light, as listed below.

//////////////////////////////////////////////////////
// This is a demo object. As long as it contains 
// CMRTObject in its base classes, the multitrack works.
// Implement your own Draw fct, with your datas, etc..
// If derived from CObject, the serialize capacities can 
// be added.
//
class CDemoObject : public CMRTObject, public CObject
{
public:
 CDemoObject (COLORREF rgb)
 : CMRTObject(), m_color(rgb) {;}
 CDemoObject (LPCRECT lpSrcRect, COLORREF rgb)
 : CMRTObject(lpSrcRect), m_color(rgb) {;}

 ~CDemoObject () {;}

public:
 void Draw (CDC* pDC) {
 pDC->FillSolidRect (GetRect(), m_color);
}

protected:
 COLORREF m_color;
};

Listed below is a possible implementation for your CxxView::OnLButtonDown().
It performs multiple selection with a local CRectTracker, and updates the
CMultiRectTracker object contained by the view. If there is no rubber band,
it selects the object clicked, and if the HitTest is different than -1
(CRectTracker::hitNothing), it starts the CMultiRectTracker::Track() function,
wich contains the similar internal loop than CRectTracker. All objects
moved or sized are directly updated in the Track() fct, the only work the
CxxView needs to do is a call to Invalidate(). The CTRL key is scanned,
and selected objects are removed if the user don’t hit CTRL.

void CDemoView::OnLButtonDown(UINT nFlags, CPoint point)
{
 CDemoDoc* pDoc = GetDocument();

 // Ask the multitrack if an object is already 
 // selected or a handle. If not, start the 
 // local tracker. 
 if (multiTrack.HitTest(point) < 0) {

  // Reset the multitrack only if there 
  // is no CTRL key. 
  if (!(nFlags & MK_CONTROL))
   multiTrack.RemoveAll();

  CRect rcObject;
  CDemoObject* pObject;

  // local tracker... 
  CRectTracker tracker;
  if (tracker.TrackRubberBand(this, point, TRUE)) {

   // see if rubber band intersects with the objects 
   CRect rectT;
   tracker.m_rect.NormalizeRect();
   POSITION pos = pDoc->m_objects.GetHeadPosition ();
   while (pos != NULL) {
    pObject = (CDemoObject*)(pDoc->m_objects.GetNext(pos));
    rcObject = pObject->GetRect();
    rectT.IntersectRect(tracker.m_rect, rcObject);
    if (rectT == rcObject) {
     multiTrack.Add(pObject); // add it to the multitrack, 
     // and continue the loop 
    }
   }
  } else {
   // No rubber band, see if the point selects an object. 
   POSITION pos = pDoc->m_objects.GetHeadPosition ();
   while (pos != NULL) {
    pObject = (CDemoObject*)(pDoc->m_objects.GetNext(pos));
    rcObject = pObject->GetRect();
    if (rcObject.PtInRect(point)) {
		 // add just one object to the multitrack 
     multiTrack.Add(pObject);
     break;
    }
   }
  }
 } else {
  // Click on the multitrack, forward actions to it. 
  if (multiTrack.Track(this, point, FALSE))
  pDoc->SetModifiedFlag();
 }
 // Update drawing. 
 Invalidate();
 CView::OnLButtonDown(nFlags, point);
}

In order to be classic, the cursor needs to be updated, function of
its position on the objects, so a call to SetCursor() is needed before
the CView-base class OnSetCursor() call, like the CRectTracker usage.

BOOL CDemoView::OnSetCursor(CWnd* pWnd, UINT nHitTest,
 UINT message)
{
 // forward to multitracker 
 if (pWnd == this && multiTrack.SetCursor(this, nHitTest))
 return TRUE;
 return CView::OnSetCursor(pWnd, nHitTest, message);
}

Downloads

Download demo project – 34 Kb
Download source – 5 Kb

CodeGuru Logo

CodeGuru covers topics related to Microsoft-related software development, mobile development, database management, and web application programming. In addition to tutorials and how-tos that teach programmers how to code in Microsoft-related languages and frameworks like C# and .Net, we also publish articles on software development tools, the latest in developer news, and advice for project managers. Cloud services such as Microsoft Azure and database options including SQL Server and MSSQL are also frequently covered.

Property of TechnologyAdvice. © 2026 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.