65.9K
CodeProject 正在变化。 阅读更多。
Home

动态线条绘制 ActiveX 控件

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.05/5 (6投票s)

2007年1月15日

3分钟阅读

viewsIcon

36511

downloadIcon

1491

用于在运行时绘制线条的 ActiveX 控件

Sample Image - TestLine_Activex.gif

引言

我见过简单的 ActiveX 控件示例,提供了各种形状的设计时绘图。在这个例子中,我尝试以一种非常简单的方式在运行时创建一条直线,当 ActiveX 控件的类被使用时,即像在 MS Word 中使用绘图工具一样在您的应用程序中绘制一条直线。您可以调整直线的大小和移动直线。此处也附带一个使用此 ActiveX 的简单示例。此示例可以扩展到任何形状。

背景

当我想在图表上创建简单的线条用于各种曲线计算时,我想创建一个简单的直线绘图 ActiveX 控件,该控件将帮助用户在运行时绘制直线,并根据直线和曲线的交点、投影等获取结果。

Using the Code

下载 ActiveX 演示并编译 VC 6.0 中的 TestLine.dsw,它将创建 TestLine ActiveX 控件,然后编译 VC 6.0 中的 TestDlg.dsw 以查看此 ActiveX 控件的演示。单击“Line”按钮按下左键,然后根据需要移动鼠标,然后释放鼠标,TestLine 控件将根据此操作创建。双击该线将提供调整大小或移动该线的选项。

源代码说明

当鼠标双击该线时,

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();
 }
 ...

如果鼠标左键按在线的中间,则移动该线,否则如果鼠标左键按在线的任何一端,则将该线重绘到释放鼠标的位置。

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;
          }
     }
 }
 //...
 //...
}

如果设置了 drawLine 变量,则在鼠标移动时在父级上绘制一条线,移除旧的线,释放鼠标后将控件移动到新位置并擦除该线。

如果设置了 moveLine 变量,则将该线移动到新位置。

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);
}

一旦释放左键,将 drawLine 或 moveLine 变量设置为 false(如果之前已设置),并将控件窗口的区域设置为该线的区域。

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

在运行时绘制直线和 node_point,onDraw 不会被调用,onPaint 将被调用用于在控件上绘图。

// 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);
// }
//

使用该代码的示例应用程序:TestDlg:<BR>
1. 创建一个名为 Line 的按钮:单击该按钮时,将 drawLine 变量设置为 true


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

2. 在鼠标左键按下时,记录第一个点

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

3. 通过按下鼠标左键移动鼠标,记录第二个点。

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

4. 现在使用这两个指定的点创建控件

//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);
//}

我学到的最重要的事情是理解用户操作并创建组合区域,并为该线控件的窗口设置它。这是我尝试以尽可能简单的方式创建控件的快速尝试。它可能会遇到一些错误,因为它没有在所有环境中进行测试。我学到的最重要的事情是理解用户操作并创建组合区域,并为该线控件的窗口设置它。

© . All rights reserved.