Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Dynamic Line Drawing Activex Control

0.00/5 (No votes)
15 Jan 2007 1  
Activex Control for Line Drawing at runtime

Sample Image - TestLine_Activex.gif

Introduction

For simple ActiveX Control�s example, I have seen, provides design time drawing of various shapes. In this example I tried to do in a very simple way to create a Line at runtime when the ActiveX control�s class is used, i.e. drawing a line in your application at runtime like it happens in MS Word using drawing tool. You can resize the line and move the line. A simple example for using this ActiveX is also attached herewith. This example can be extended to any shapes.

Background

When I have to create simple lines on the graph for various calculation of curves thought to create a simple line drawing ActiveX control which would help the user to draw the line at run time and get the results based on the line and curve intersections, projection etc.

Using the Code:

Download the ActiveX demo and compile the TestLine.dsw in VC 6.0 it will create the TestLine ActiveX control and then compile the TestDlg.dsw in VC 6.0 to see the demo of this ActiveX controls working. Click on the �Line� button to press the left button and move the mouse as you like and release the same a TestLine Control is created base on this operation. Double clicking on the line will provide option to resize of move the line.

Source Code Description

When the mouse is double clicked over the line, then:

void CTestLineCtrl::OnLButtonDblClk(UINT nFlags, CPoint point)
{
 // node_points variable is set so that nodal points can be drawn

 // for resizing or moving operation

 if (!node_points)
 {
     node_points = true;
     Invalidate();
 }
 ...

If the left mouse button is pressed on the middle of the line then moved the line is moved else if the left mouse button pressed on any of the ends of the line then the line is redrawn till the point where the mouse is released.

void CTestLineCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
 if (node_points)
 {
     // moving the control....!

     if (nodeRectMid.PtInRect(point))
     {
       moveLine = true;
       //save current cursor coordinate

       mPoint1 = point;
       ClientToScreen(&mPoint1); //pMsg->pt;

       mPoint2 = mPoint1;
     } else {// re-drawing the line..

         if (nodeRect1.PtInRect(point))
         {
           //node_points = false;

           lPoint1 = lPoint2;
           lPoint2 = point;
           drawLine = true;
         } else if (nodeRect2.PtInRect(point)) {
           //node_points = false;

           drawLine = true;
          }
     }
 }
 //...

 //...

}

If drawLine variable is set then on Mouse move draw a line on the parent by removing the old once the mouse is release move the control to the new position and erase the line.

If moveLine variable is set then move the line to the new position.

CTestLineCtrl::OnMouseMove(UINT nFlags, CPoint point)
{
 if (drawLine)
 {
     CWnd* prnt = GetParent();
     // Draw the dotted line..! on the parent...!

     CPoint p1, p2, p3;
     // Get the first point and

     // then get the new point

     p1 = lPoint1;
     p2 = lPoint3;
     p3 = point;
     ClientToScreen(&p1);
     ClientToScreen(&p3);
     // store this point in terms

     // of screen for next use..!

     lPoint3 = p3;

     // Make the point for the parent.

     if (prnt)
     {
      prnt->ScreenToClient(&p1);
      prnt->ScreenToClient(&p2);
      prnt->ScreenToClient(&p3);
     }
     // Get the device context of the parent

     CDC *pdc = prnt->GetDC();
    
     // Redraw the old region

     int xEpsilon = 0;
     int yEpsilon = 0;
     CPoint pts[5];
    
     if (p2.x > p1.x )
     {
      xEpsilon = -2;
     } else {
      xEpsilon = 2;
     }
    
     if (p1.y > p1.y)
     {
      yEpsilon = -2;
     } else {
      yEpsilon = 2;
     }

 pts[0].x = p1.x + xEpsilon;
 pts[0].y = p1.y ;

 pts[1].x = p1.x + xEpsilon;
 pts[1].y = p1.y + yEpsilon;

 pts[2].x = p2.x - xEpsilon;
 pts[2].y = p2.y + yEpsilon;

 pts[3].x = p2.x - xEpsilon;
 pts[3].y = p2.y ;

 pts[4].x = pts[0].x;
 pts[4].y = pts[0].y;

 CRgn *rgn;
 rgn = new CRgn();
 rgn->CreatePolygonRgn(pts, 5, WINDING);
 prnt->InvalidateRgn(rgn);

 //prnt->Invalidate();

 // Draw the line..!


 CPen *myPen = new CPen(PS_DASH, 1, RGB(0, 0, 0));
 CPen* OldPen = pdc->SelectObject(myPen);

 pdc->MoveTo(p1.x, p1.y);
 pdc->LineTo(p3.x, p3.y);

 delete rgn;
 pdc->SelectObject(OldPen);
 delete myPen;
 }

 if(moveLine)
 {
  CWnd* prnt = GetParent();
  GetWindowRect(&MainRect);
  CPoint temp;
  temp.x = MainRect.left ;
  temp.y = MainRect.top ;

  if (prnt)
    prnt->ScreenToClient(&temp);

  int chX = (mPoint2.x - mPoint1.x);
  int chY = (mPoint2.y - mPoint1.y);

  mPoint1 = mPoint2;
  mPoint2 = point;
  ClientToScreen(&mPoint2); //pMsg->pt;


  MoveWindow(temp.x + chX,
  //count the relative position

  temp.y + chY,
  MainRect.Width(),
  //if the width doesn�t change

  MainRect.Height(),
  //if the height doesn�t change

  TRUE);
}

Once the left button is release set the drawLine or moveLine variable to false if they were previously set and set the region of Control window to that of line.

// // Now the rect is found change the window position and size
// // Set the window
// MoveWindow(temp.x,
// temp.y,
// w,
// h,
// FALSE);
//
// ...
//
// SetTheLineRgn();

Draw the line and node_point At runtime onDraw will not be called onPaint will be called for drawing on the control.

// dc.MoveTo(lPoint1.x, lPoint1.y);
// dc.LineTo(lPoint2.x, lPoint2.y);
//
//
// if (node_points)
// {
// if ((lPoint1.x != lPoint2.x) || (lPoint1.y != lPoint2.y))
// {
//
// CalculateNodeAreas();
// dc.Rectangle(nodeRect1);
// dc.Rectangle(nodeRectMid);
// dc.Rectangle(nodeRect2);
// }
//

Sample application to use the code: TestDlg:<BR>
1. Create a Button called Line: On clicking on the button set the drawLine variable to true:


//OnDrawline()
//{
// // preparing to draw the line
// <code>drawLine = true;</code>
//}

2. On left button down record the first point

//void CTestDlg::OnLButtonDown(UINT nFlags, CPoint point)
//{
// // Record the first point.
// if (drawLine)
// {
// <code>p1 = point;</code>
// }
//...
//}

3. On mouse move by pressing the left button record the second point.

//void CTestDlg::OnMouseMove(UINT nFlags, CPoint point)
//{
// if (drawLine && nFlags == MK_LBUTTON)
// {
// <code>p2 = point;</code>
// Invalidate();
// }
//
//...
//}

4 Now create the control with those to specified point

//void CTestDlg::OnLButtonUp(UINT nFlags, CPoint point)
//{
// if (drawLine)
// {
// drawLine = false;
// p2 = point;
// if (lineIndex < MAX_NO_OF_LINE)
// {
// myLine[lineIndex] = new CTestLine();
// CTestLine* tLine = myLine[lineIndex];
// lineIndex++;
//
// int x1, x2, y1, y2;
// CRect rect;
// if (p2.x > p1.x)
// {
// rect.left = p1.x;
// rect.right = p2.x;
// x1 = 0;
// x2 = p2.x - p1.x;
// } else {
// rect.left = p2.x;
// rect.right = p1.x;
// x1 = 0;
// x2 = p1.x - p2.x;
// }
//
// if (p2.y > p1.y)
// {
// rect.top = p1.y;
// rect.bottom = p2.y;
// y1 = 0;
// y2 = p2.y - p1.y;
// } else {
// rect.top = p2.y;
// rect.bottom = p1.y;
// y1 = 0;
// y2 = p1.y - p2.y;
// }
//
// tLine->Create("testLine", WS_CHILD | WS_VISIBLE, rect, this, 10, NULL);
// tLine->ShowWindow(SW_SHOWNORMAL);
// ClientToScreen(&p1);
// ClientToScreen(&p2);
// tLine->ScreenToClient(&p1);
// tLine->ScreenToClient(&p2);
// tLine->SetPoint1(p1.x, p1.y);
// tLine->SetPoint2(p2.x, p2.y);
// tLine->Invalidate();
//
// } else {
// MessageBox("Unable to draw Line. Increase the No of Line!");
// }
//
// Invalidate();
//
// }
// CDialog::OnLButtonUp(nFlags, point);
//}

Most important thing I learnt that understating the user operation and creating the combined region and setting the same for that line control�s window. This is my quick try to create the control as simple way as it can be. It might encounter to some bugs as it is not tested in all the environments. Most important thing I learnt that understating the user operation and creating the combined region and setting the same for that line control�s window.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here